summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/subtables/chaining/read.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/subtables/chaining/read.c')
-rw-r--r--Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/subtables/chaining/read.c416
1 files changed, 416 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/subtables/chaining/read.c b/Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/subtables/chaining/read.c
new file mode 100644
index 00000000000..0059efeaec9
--- /dev/null
+++ b/Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/subtables/chaining/read.c
@@ -0,0 +1,416 @@
+#include "../chaining.h"
+#include "common.h"
+
+typedef struct {
+ otl_ClassDef *bc;
+ otl_ClassDef *ic;
+ otl_ClassDef *fc;
+} classdefs;
+
+static otl_Coverage *singleCoverage(font_file_pointer data, uint32_t tableLength, uint16_t gid,
+ uint32_t _offset, uint16_t kind, const glyphid_t maxGlyphs,
+ void *userdata) {
+ otl_Coverage *cov;
+ NEW(cov);
+ cov->numGlyphs = 1;
+ NEW(cov->glyphs);
+ cov->glyphs[0] = Handle.fromIndex((glyphid_t)gid);
+ return cov;
+}
+static otl_Coverage *classCoverage(font_file_pointer data, uint32_t tableLength, uint16_t cls,
+ uint32_t _offset, uint16_t kind, const glyphid_t maxGlyphs,
+ void *_classdefs) {
+ classdefs *defs = (classdefs *)_classdefs;
+ otl_ClassDef *cd = (kind == 1 ? defs->bc : kind == 2 ? defs->ic : defs->fc);
+ otl_Coverage *cov;
+ NEW(cov);
+ cov->numGlyphs = 0;
+ cov->glyphs = NULL;
+ glyphid_t count = 0;
+ if (cls == 0) {
+ for (glyphid_t k = 0; k < maxGlyphs; k++) {
+ bool found = false;
+ for (glyphid_t j = 0; j < cd->numGlyphs; j++) {
+ if (cd->classes[j] > 0 && cd->glyphs[j].index == k) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) count += 1;
+ }
+ } else {
+ for (glyphid_t j = 0; j < cd->numGlyphs; j++) {
+ if (cd->classes[j] == cls) count++;
+ }
+ }
+ if (!count) return cov;
+
+ cov->numGlyphs = count;
+ NEW(cov->glyphs, count);
+ glyphid_t jj = 0;
+ if (cls == 0) {
+ for (glyphid_t k = 0; k < maxGlyphs; k++) {
+ bool found = false;
+ for (glyphid_t j = 0; j < cd->numGlyphs; j++) {
+ if (cd->classes[j] > 0 && cd->glyphs[j].index == k) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) cov->glyphs[jj++] = Handle.fromIndex(k);
+ }
+ } else {
+ for (glyphid_t j = 0; j < cd->numGlyphs; j++) {
+ if (cd->classes[j] == cls) { cov->glyphs[jj++] = Handle.dup(cd->glyphs[j]); }
+ }
+ }
+ return cov;
+}
+static otl_Coverage *format3Coverage(font_file_pointer data, uint32_t tableLength, uint16_t shift,
+ uint32_t _offset, uint16_t kind, const glyphid_t maxGlyphs,
+ void *userdata) {
+ return Coverage.read(data, tableLength, _offset + shift - 2);
+}
+
+typedef otl_Coverage *(*CoverageReaderHandler)(font_file_pointer, uint32_t, uint16_t, uint32_t,
+ uint16_t, glyphid_t, void *);
+
+static otl_ChainingRule *GeneralReadContextualRule(font_file_pointer data, uint32_t tableLength,
+ uint32_t offset, uint16_t startGID, bool minusOne,
+ CoverageReaderHandler fn, const glyphid_t maxGlyphs,
+ void *userdata) {
+ otl_ChainingRule *rule;
+ NEW(rule);
+ rule->match = NULL;
+ rule->apply = NULL;
+
+ uint16_t minusOneQ = (minusOne ? 1 : 0);
+
+ checkLength(offset + 4);
+ uint16_t nInput = read_16u(data + offset);
+ uint16_t nApply = read_16u(data + offset + 2);
+ checkLength(offset + 4 + 2 * nInput + 4 * nApply);
+
+ rule->matchCount = nInput;
+ rule->inputBegins = 0;
+ rule->inputEnds = nInput;
+
+ NEW(rule->match, rule->matchCount);
+ uint16_t jj = 0;
+ if (minusOne) {
+ rule->match[jj++] = fn(data, tableLength, startGID, offset, 2, maxGlyphs, userdata);
+ }
+ for (uint16_t j = 0; j < nInput - minusOneQ; j++) {
+ uint32_t gid = read_16u(data + offset + 4 + j * 2);
+ rule->match[jj++] = fn(data, tableLength, gid, offset, 2, maxGlyphs, userdata);
+ }
+ rule->applyCount = nApply;
+ NEW(rule->apply, rule->applyCount);
+ for (tableid_t j = 0; j < nApply; j++) {
+ rule->apply[j].index =
+ rule->inputBegins +
+ read_16u(data + offset + 4 + 2 * (rule->matchCount - minusOneQ) + j * 4);
+ rule->apply[j].lookup = Handle.fromIndex(
+ read_16u(data + offset + 4 + 2 * (rule->matchCount - minusOneQ) + j * 4 + 2));
+ }
+ reverseBacktracks(rule);
+ return rule;
+
+FAIL:
+ DELETE(deleteRule, rule);
+ return NULL;
+}
+static subtable_chaining *readContextualFormat1(subtable_chaining *subtable,
+ const font_file_pointer data, uint32_t tableLength,
+ uint32_t offset, const glyphid_t maxGlyphs) {
+ // Contextual Substitution Subtable, Simple.
+ checkLength(offset + 6);
+
+ uint16_t covOffset = offset + read_16u(data + offset + 2);
+ otl_Coverage *firstCoverage = Coverage.read(data, tableLength, covOffset);
+
+ tableid_t chainSubRuleSetCount = read_16u(data + offset + 4);
+ if (chainSubRuleSetCount != firstCoverage->numGlyphs) goto FAIL;
+ checkLength(offset + 6 + 2 * chainSubRuleSetCount);
+
+ tableid_t totalRules = 0;
+ for (tableid_t j = 0; j < chainSubRuleSetCount; j++) {
+ uint32_t srsOffset = offset + read_16u(data + offset + 6 + j * 2);
+ checkLength(srsOffset + 2);
+ totalRules += read_16u(data + srsOffset);
+ checkLength(srsOffset + 2 + 2 * read_16u(data + srsOffset));
+ }
+ subtable->rulesCount = totalRules;
+ NEW(subtable->rules, totalRules);
+
+ tableid_t jj = 0;
+ for (tableid_t j = 0; j < chainSubRuleSetCount; j++) {
+ uint32_t srsOffset = offset + read_16u(data + offset + 6 + j * 2);
+ tableid_t srsCount = read_16u(data + srsOffset);
+ for (tableid_t k = 0; k < srsCount; k++) {
+ uint32_t srOffset = srsOffset + read_16u(data + srsOffset + 2 + k * 2);
+ subtable->rules[jj] = GeneralReadContextualRule(data, tableLength, srOffset,
+ firstCoverage->glyphs[j].index, true,
+ singleCoverage, maxGlyphs, NULL);
+ jj += 1;
+ }
+ }
+
+ Coverage.free(firstCoverage);
+ return subtable;
+FAIL:
+ iSubtable_chaining.free(subtable);
+ return NULL;
+}
+static subtable_chaining *readContextualFormat2(subtable_chaining *subtable,
+ const font_file_pointer data, uint32_t tableLength,
+ uint32_t offset, const glyphid_t maxGlyphs) {
+ // Contextual Substitution Subtable, Class based.
+ checkLength(offset + 8);
+
+ classdefs *cds;
+ NEW(cds);
+ cds->bc = NULL;
+ cds->ic = ClassDef.read(data, tableLength, offset + read_16u(data + offset + 4));
+ cds->fc = NULL;
+
+ tableid_t chainSubClassSetCnt = read_16u(data + offset + 6);
+ checkLength(offset + 12 + 2 * chainSubClassSetCnt);
+
+ tableid_t totalRules = 0;
+ for (tableid_t j = 0; j < chainSubClassSetCnt; j++) {
+ uint32_t srcOffset = read_16u(data + offset + 8 + j * 2);
+ if (srcOffset) { totalRules += read_16u(data + offset + srcOffset); }
+ }
+ subtable->rulesCount = totalRules;
+ NEW(subtable->rules, totalRules);
+
+ tableid_t jj = 0;
+ for (tableid_t j = 0; j < chainSubClassSetCnt; j++) {
+ uint32_t srcOffset = read_16u(data + offset + 8 + j * 2);
+ if (srcOffset) {
+ tableid_t srsCount = read_16u(data + offset + srcOffset);
+ for (tableid_t k = 0; k < srsCount; k++) {
+ uint32_t srOffset =
+ offset + srcOffset + read_16u(data + offset + srcOffset + 2 + k * 2);
+ subtable->rules[jj] = GeneralReadContextualRule(
+ data, tableLength, srOffset, j, true, classCoverage, maxGlyphs, cds);
+ jj += 1;
+ }
+ }
+ }
+ if (cds) {
+ if (cds->bc) ClassDef.free(cds->bc);
+ if (cds->ic) ClassDef.free(cds->ic);
+ if (cds->fc) ClassDef.free(cds->fc);
+ FREE(cds);
+ }
+ return subtable;
+FAIL:
+ iSubtable_chaining.free(subtable);
+ return NULL;
+}
+otl_Subtable *otl_read_contextual(const font_file_pointer data, uint32_t tableLength,
+ uint32_t offset, const glyphid_t maxGlyphs,
+ const otfcc_Options *options) {
+ uint16_t format = 0;
+ subtable_chaining *subtable = iSubtable_chaining.create();
+ subtable->type = otl_chaining_poly;
+
+ checkLength(offset + 2);
+ format = read_16u(data + offset);
+ if (format == 1) {
+ return (otl_Subtable *)readContextualFormat1(subtable, data, tableLength, offset,
+ maxGlyphs);
+ } else if (format == 2) {
+ return (otl_Subtable *)readContextualFormat2(subtable, data, tableLength, offset,
+ maxGlyphs);
+ } else if (format == 3) {
+ // Contextual Substitution Subtable, Coverage based.
+ subtable->rulesCount = 1;
+ NEW(subtable->rules, 1);
+ subtable->rules[0] = GeneralReadContextualRule(data, tableLength, offset + 2, 0, false,
+ format3Coverage, maxGlyphs, NULL);
+ return (otl_Subtable *)subtable;
+ }
+FAIL:
+ logWarning("Unsupported format %d.\n", format);
+ iSubtable_chaining.free(subtable);
+ return NULL;
+}
+
+static otl_ChainingRule *GeneralReadChainingRule(font_file_pointer data, uint32_t tableLength,
+ uint32_t offset, uint16_t startGID, bool minusOne,
+ CoverageReaderHandler fn, const glyphid_t maxGlyphs,
+ void *userdata) {
+ otl_ChainingRule *rule;
+ NEW(rule);
+ rule->match = NULL;
+ rule->apply = NULL;
+
+ uint16_t minusOneQ = (minusOne ? 1 : 0);
+
+ checkLength(offset + 8);
+ tableid_t nBack = read_16u(data + offset);
+ checkLength(offset + 2 + 2 * nBack + 2);
+ tableid_t nInput = read_16u(data + offset + 2 + 2 * nBack);
+ checkLength(offset + 4 + 2 * (nBack + nInput - minusOneQ) + 2);
+ tableid_t nLookaround = read_16u(data + offset + 4 + 2 * (nBack + nInput - minusOneQ));
+ checkLength(offset + 6 + 2 * (nBack + nInput - minusOneQ + nLookaround) + 2);
+ tableid_t nApply = read_16u(data + offset + 6 + 2 * (nBack + nInput - minusOneQ + nLookaround));
+ checkLength(offset + 8 + 2 * (nBack + nInput - minusOneQ + nLookaround) + nApply * 4);
+
+ rule->matchCount = nBack + nInput + nLookaround;
+ rule->inputBegins = nBack;
+ rule->inputEnds = nBack + nInput;
+
+ NEW(rule->match, rule->matchCount);
+ tableid_t jj = 0;
+ for (tableid_t j = 0; j < nBack; j++) {
+ uint32_t gid = read_16u(data + offset + 2 + j * 2);
+ rule->match[jj++] = fn(data, tableLength, gid, offset, 1, maxGlyphs, userdata);
+ }
+ if (minusOne) {
+ rule->match[jj++] = fn(data, tableLength, startGID, offset, 2, maxGlyphs, userdata);
+ }
+ for (tableid_t j = 0; j < nInput - minusOneQ; j++) {
+ uint32_t gid = read_16u(data + offset + 4 + 2 * rule->inputBegins + j * 2);
+ rule->match[jj++] = fn(data, tableLength, gid, offset, 2, maxGlyphs, userdata);
+ }
+ for (tableid_t j = 0; j < nLookaround; j++) {
+ uint32_t gid = read_16u(data + offset + 6 + 2 * (rule->inputEnds - minusOneQ) + j * 2);
+ rule->match[jj++] = fn(data, tableLength, gid, offset, 3, maxGlyphs, userdata);
+ }
+ rule->applyCount = nApply;
+ NEW(rule->apply, rule->applyCount);
+ for (tableid_t j = 0; j < nApply; j++) {
+ rule->apply[j].index =
+ rule->inputBegins +
+ read_16u(data + offset + 8 + 2 * (rule->matchCount - minusOneQ) + j * 4);
+ rule->apply[j].lookup = Handle.fromIndex(
+ read_16u(data + offset + 8 + 2 * (rule->matchCount - minusOneQ) + j * 4 + 2));
+ }
+ reverseBacktracks(rule);
+ return rule;
+
+FAIL:
+ DELETE(deleteRule, rule);
+ return NULL;
+}
+static subtable_chaining *readChainingFormat1(subtable_chaining *subtable,
+ const font_file_pointer data, uint32_t tableLength,
+ uint32_t offset, const glyphid_t maxGlyphs) {
+ // Contextual Substitution Subtable, Simple.
+ checkLength(offset + 6);
+
+ uint16_t covOffset = offset + read_16u(data + offset + 2);
+ otl_Coverage *firstCoverage = Coverage.read(data, tableLength, covOffset);
+
+ tableid_t chainSubRuleSetCount = read_16u(data + offset + 4);
+ if (chainSubRuleSetCount != firstCoverage->numGlyphs) goto FAIL;
+ checkLength(offset + 6 + 2 * chainSubRuleSetCount);
+
+ tableid_t totalRules = 0;
+ for (tableid_t j = 0; j < chainSubRuleSetCount; j++) {
+ uint32_t srsOffset = offset + read_16u(data + offset + 6 + j * 2);
+ checkLength(srsOffset + 2);
+ totalRules += read_16u(data + srsOffset);
+ checkLength(srsOffset + 2 + 2 * read_16u(data + srsOffset));
+ }
+ subtable->rulesCount = totalRules;
+ NEW(subtable->rules, totalRules);
+
+ tableid_t jj = 0;
+ for (tableid_t j = 0; j < chainSubRuleSetCount; j++) {
+ uint32_t srsOffset = offset + read_16u(data + offset + 6 + j * 2);
+ tableid_t srsCount = read_16u(data + srsOffset);
+ for (tableid_t k = 0; k < srsCount; k++) {
+ uint32_t srOffset = srsOffset + read_16u(data + srsOffset + 2 + k * 2);
+ subtable->rules[jj] =
+ GeneralReadChainingRule(data, tableLength, srOffset, firstCoverage->glyphs[j].index,
+ true, singleCoverage, maxGlyphs, NULL);
+ jj += 1;
+ }
+ }
+
+ Coverage.free(firstCoverage);
+ return subtable;
+FAIL:
+ iSubtable_chaining.free(subtable);
+ return NULL;
+}
+static subtable_chaining *readChainingFormat2(subtable_chaining *subtable,
+ const font_file_pointer data, uint32_t tableLength,
+ uint32_t offset, const glyphid_t maxGlyphs) {
+ // Chaining Contextual Substitution Subtable, Class based.
+ checkLength(offset + 12);
+
+ classdefs *cds;
+ NEW(cds);
+ cds->bc = ClassDef.read(data, tableLength, offset + read_16u(data + offset + 4));
+ cds->ic = ClassDef.read(data, tableLength, offset + read_16u(data + offset + 6));
+ cds->fc = ClassDef.read(data, tableLength, offset + read_16u(data + offset + 8));
+
+ tableid_t chainSubClassSetCnt = read_16u(data + offset + 10);
+ checkLength(offset + 12 + 2 * chainSubClassSetCnt);
+
+ tableid_t totalRules = 0;
+ for (tableid_t j = 0; j < chainSubClassSetCnt; j++) {
+ uint32_t srcOffset = read_16u(data + offset + 12 + j * 2);
+ if (srcOffset) { totalRules += read_16u(data + offset + srcOffset); }
+ }
+ subtable->rulesCount = totalRules;
+ NEW(subtable->rules, totalRules);
+
+ tableid_t jj = 0;
+ for (tableid_t j = 0; j < chainSubClassSetCnt; j++) {
+ uint32_t srcOffset = read_16u(data + offset + 12 + j * 2);
+ if (srcOffset) {
+ tableid_t srsCount = read_16u(data + offset + srcOffset);
+ for (tableid_t k = 0; k < srsCount; k++) {
+ uint32_t dsrOffset = read_16u(data + offset + srcOffset + 2 + k * 2);
+ uint32_t srOffset = offset + srcOffset + dsrOffset;
+ subtable->rules[jj] = GeneralReadChainingRule(data, tableLength, srOffset, j, true,
+ classCoverage, maxGlyphs, cds);
+ jj += 1;
+ }
+ }
+ }
+
+ if (cds) {
+ if (cds->bc) ClassDef.free(cds->bc);
+ if (cds->ic) ClassDef.free(cds->ic);
+ if (cds->fc) ClassDef.free(cds->fc);
+ FREE(cds);
+ }
+ return subtable;
+FAIL:
+ iSubtable_chaining.free(subtable);
+ return NULL;
+}
+otl_Subtable *otl_read_chaining(const font_file_pointer data, uint32_t tableLength, uint32_t offset,
+ const glyphid_t maxGlyphs, const otfcc_Options *options) {
+ uint16_t format = 0;
+ subtable_chaining *subtable = iSubtable_chaining.create();
+ subtable->type = otl_chaining_poly;
+
+ checkLength(offset + 2);
+ format = read_16u(data + offset);
+ if (format == 1) {
+ return (otl_Subtable *)readChainingFormat1(subtable, data, tableLength, offset, maxGlyphs);
+ } else if (format == 2) {
+ return (otl_Subtable *)readChainingFormat2(subtable, data, tableLength, offset, maxGlyphs);
+ } else if (format == 3) {
+ // Chaining Contextual Substitution Subtable, Coverage based.
+ // This table has exactly one rule within it, and i love it.
+ subtable->rulesCount = 1;
+ NEW(subtable->rules, 1);
+ subtable->rules[0] = GeneralReadChainingRule(data, tableLength, offset + 2, 0, false,
+ format3Coverage, maxGlyphs, NULL);
+ return (otl_Subtable *)subtable;
+ }
+FAIL:
+ logWarning("Unsupported format %d.\n", format);
+ iSubtable_chaining.free(subtable);
+ return NULL;
+}