summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/subtables/gpos-mark-to-single.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/subtables/gpos-mark-to-single.c')
-rw-r--r--Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/subtables/gpos-mark-to-single.c203
1 files changed, 203 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/subtables/gpos-mark-to-single.c b/Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/subtables/gpos-mark-to-single.c
new file mode 100644
index 00000000000..cf55cde82dc
--- /dev/null
+++ b/Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/subtables/gpos-mark-to-single.c
@@ -0,0 +1,203 @@
+#include "gpos-mark-to-single.h"
+#include "gpos-common.h"
+
+static void deleteBaseArrayItem(otl_BaseRecord *entry) {
+ Handle.dispose(&entry->glyph);
+ FREE(entry->anchors);
+}
+static caryll_ElementInterface(otl_BaseRecord) ba_typeinfo = {
+ .init = NULL, .copy = NULL, .dispose = deleteBaseArrayItem};
+
+caryll_standardVectorImpl(otl_BaseArray, otl_BaseRecord, ba_typeinfo, otl_iBaseArray);
+
+static INLINE void initMarkToSingle(subtable_gpos_markToSingle *subtable) {
+ otl_iMarkArray.init(&subtable->markArray);
+ otl_iBaseArray.init(&subtable->baseArray);
+}
+static INLINE void disposeMarkToSingle(subtable_gpos_markToSingle *subtable) {
+ otl_iMarkArray.dispose(&subtable->markArray);
+ otl_iBaseArray.dispose(&subtable->baseArray);
+}
+
+caryll_standardRefType(subtable_gpos_markToSingle, iSubtable_gpos_markToSingle, initMarkToSingle,
+ disposeMarkToSingle);
+
+otl_Subtable *otl_read_gpos_markToSingle(const font_file_pointer data, uint32_t tableLength,
+ uint32_t subtableOffset, const glyphid_t maxGlyphs,
+ const otfcc_Options *options) {
+
+ subtable_gpos_markToSingle *subtable = iSubtable_gpos_markToSingle.create();
+ otl_Coverage *marks = NULL;
+ otl_Coverage *bases = NULL;
+
+ if (tableLength < subtableOffset + 12) goto FAIL;
+ marks = Coverage.read(data, tableLength, subtableOffset + read_16u(data + subtableOffset + 2));
+ bases = Coverage.read(data, tableLength, subtableOffset + read_16u(data + subtableOffset + 4));
+ if (!marks || marks->numGlyphs == 0 || !bases || bases->numGlyphs == 0) goto FAIL;
+
+ subtable->classCount = read_16u(data + subtableOffset + 6);
+ uint32_t markArrayOffset = subtableOffset + read_16u(data + subtableOffset + 8);
+ otl_readMarkArray(&subtable->markArray, marks, data, tableLength, markArrayOffset);
+
+ uint32_t baseArrayOffset = subtableOffset + read_16u(data + subtableOffset + 10);
+ checkLength(baseArrayOffset + 2 + 2 * bases->numGlyphs * subtable->classCount);
+ if (read_16u(data + baseArrayOffset) != bases->numGlyphs) goto FAIL;
+
+ uint32_t _offset = baseArrayOffset + 2;
+ for (glyphid_t j = 0; j < bases->numGlyphs; j++) {
+ otl_Anchor *baseAnchors;
+ NEW(baseAnchors, subtable->classCount);
+ for (glyphclass_t k = 0; k < subtable->classCount; k++) {
+ if (read_16u(data + _offset)) {
+ baseAnchors[k] =
+ otl_read_anchor(data, tableLength, baseArrayOffset + read_16u(data + _offset));
+ } else {
+ baseAnchors[k] = otl_anchor_absent();
+ }
+ _offset += 2;
+ }
+ otl_iBaseArray.push(
+ &subtable->baseArray,
+ ((otl_BaseRecord){.glyph = Handle.dup(bases->glyphs[j]), .anchors = baseAnchors}));
+ }
+ if (marks) Coverage.free(marks);
+ if (bases) Coverage.free(bases);
+ return (otl_Subtable *)subtable;
+FAIL:
+ iSubtable_gpos_markToSingle.free(subtable);
+ return NULL;
+}
+
+json_value *otl_gpos_dump_markToSingle(const otl_Subtable *st) {
+ const subtable_gpos_markToSingle *subtable = &(st->gpos_markToSingle);
+ json_value *_subtable = json_object_new(3);
+ json_value *_marks = json_object_new(subtable->markArray.length);
+ json_value *_bases = json_object_new(subtable->baseArray.length);
+ for (glyphid_t j = 0; j < subtable->markArray.length; j++) {
+ json_value *_mark = json_object_new(3);
+ sds markClassName =
+ sdscatfmt(sdsempty(), "anchor%i", subtable->markArray.items[j].markClass);
+ json_object_push(_mark, "class",
+ json_string_new_length((uint32_t)sdslen(markClassName), markClassName));
+ sdsfree(markClassName);
+ json_object_push(_mark, "x", json_integer_new(subtable->markArray.items[j].anchor.x));
+ json_object_push(_mark, "y", json_integer_new(subtable->markArray.items[j].anchor.y));
+ json_object_push(_marks, subtable->markArray.items[j].glyph.name, preserialize(_mark));
+ }
+ for (glyphid_t j = 0; j < subtable->baseArray.length; j++) {
+ json_value *_base = json_object_new(subtable->classCount);
+ for (glyphclass_t k = 0; k < subtable->classCount; k++) {
+ if (subtable->baseArray.items[j].anchors[k].present) {
+ json_value *_anchor = json_object_new(2);
+ json_object_push(_anchor, "x",
+ json_integer_new(subtable->baseArray.items[j].anchors[k].x));
+ json_object_push(_anchor, "y",
+ json_integer_new(subtable->baseArray.items[j].anchors[k].y));
+ sds markClassName = sdscatfmt(sdsempty(), "anchor%i", k);
+ json_object_push_length(_base, (uint32_t)sdslen(markClassName), markClassName,
+ _anchor);
+ sdsfree(markClassName);
+ }
+ }
+ json_object_push(_bases, subtable->baseArray.items[j].glyph.name, preserialize(_base));
+ }
+ json_object_push(_subtable, "marks", _marks);
+ json_object_push(_subtable, "bases", _bases);
+ return _subtable;
+}
+
+static void parseBases(json_value *_bases, subtable_gpos_markToSingle *subtable,
+ otl_ClassnameHash **h, const otfcc_Options *options) {
+ glyphclass_t classCount = HASH_COUNT(*h);
+ for (glyphid_t j = 0; j < _bases->u.object.length; j++) {
+ char *gname = _bases->u.object.values[j].name;
+ otl_BaseRecord base;
+ base.glyph = Handle.fromName(sdsnewlen(gname, _bases->u.object.values[j].name_length));
+ NEW(base.anchors, classCount);
+ for (glyphclass_t k = 0; k < classCount; k++) {
+ base.anchors[k] = otl_anchor_absent();
+ }
+ json_value *baseRecord = _bases->u.object.values[j].value;
+ if (!baseRecord || baseRecord->type != json_object) {
+ otl_iBaseArray.push(&subtable->baseArray, base);
+ continue;
+ }
+
+ for (glyphclass_t k = 0; k < baseRecord->u.object.length; k++) {
+ sds className = sdsnewlen(baseRecord->u.object.values[k].name,
+ baseRecord->u.object.values[k].name_length);
+ otl_ClassnameHash *s;
+ HASH_FIND_STR(*h, className, s);
+ if (!s) {
+ logWarning("[OTFCC-fea] Invalid anchor class name <%s> for /%s. This base anchor "
+ "is ignored.\n",
+ className, gname);
+ goto NEXT;
+ }
+ base.anchors[s->classID] = otl_parse_anchor(baseRecord->u.object.values[k].value);
+ NEXT:
+ sdsfree(className);
+ }
+ otl_iBaseArray.push(&subtable->baseArray, base);
+ }
+}
+otl_Subtable *otl_gpos_parse_markToSingle(const json_value *_subtable,
+ const otfcc_Options *options) {
+ json_value *_marks = json_obj_get_type(_subtable, "marks", json_object);
+ json_value *_bases = json_obj_get_type(_subtable, "bases", json_object);
+ if (!_marks || !_bases) return NULL;
+ subtable_gpos_markToSingle *st = iSubtable_gpos_markToSingle.create();
+ otl_ClassnameHash *h = NULL;
+ otl_parseMarkArray(_marks, &st->markArray, &h, options);
+ st->classCount = HASH_COUNT(h);
+ parseBases(_bases, st, &h, options);
+
+ otl_ClassnameHash *s, *tmp;
+ HASH_ITER(hh, h, s, tmp) {
+ HASH_DEL(h, s);
+ sdsfree(s->className);
+ FREE(s);
+ }
+
+ return (otl_Subtable *)st;
+}
+
+caryll_Buffer *otfcc_build_gpos_markToSingle(const otl_Subtable *_subtable, otl_BuildHeuristics heuristics) {
+ const subtable_gpos_markToSingle *subtable = &(_subtable->gpos_markToSingle);
+ otl_Coverage *marks = Coverage.create();
+ for (glyphid_t j = 0; j < subtable->markArray.length; j++) {
+ Coverage.push(marks, Handle.dup(subtable->markArray.items[j].glyph));
+ }
+ otl_Coverage *bases = Coverage.create();
+ for (glyphid_t j = 0; j < subtable->baseArray.length; j++) {
+ Coverage.push(bases, Handle.dup(subtable->baseArray.items[j].glyph));
+ }
+
+ bk_Block *root = bk_new_Block(b16, 1, // format
+ p16, bk_newBlockFromBuffer(Coverage.build(marks)), // markCoverage
+ p16, bk_newBlockFromBuffer(Coverage.build(bases)), // baseCoverage
+ b16, subtable->classCount, // classCont
+ bkover);
+
+ bk_Block *markArray = bk_new_Block(b16, subtable->markArray.length, // markCount
+ bkover);
+ for (glyphid_t j = 0; j < subtable->markArray.length; j++) {
+ bk_push(markArray, // markArray item
+ b16, subtable->markArray.items[j].markClass, // markClass
+ p16, bkFromAnchor(subtable->markArray.items[j].anchor), // Anchor
+ bkover);
+ }
+
+ bk_Block *baseArray = bk_new_Block(b16, subtable->baseArray.length, // baseCount
+ bkover);
+ for (glyphid_t j = 0; j < subtable->baseArray.length; j++) {
+ for (glyphclass_t k = 0; k < subtable->classCount; k++) {
+ bk_push(baseArray, p16, bkFromAnchor(subtable->baseArray.items[j].anchors[k]), bkover);
+ }
+ }
+
+ bk_push(root, p16, markArray, p16, baseArray, bkover);
+ Coverage.free(marks);
+ Coverage.free(bases);
+ return bk_build_Block(root);
+}