diff options
Diffstat (limited to 'Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/read.c')
-rw-r--r-- | Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/read.c | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/read.c b/Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/read.c new file mode 100644 index 00000000000..f1fd1f9230b --- /dev/null +++ b/Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/read.c @@ -0,0 +1,267 @@ +#include "private.h" + +#define LOOKUP_READER(llt, fn) \ + case llt: \ + return fn(data, tableLength, subtableOffset, maxGlyphs, options); + +otl_Subtable *otfcc_readOtl_subtable(font_file_pointer data, uint32_t tableLength, + uint32_t subtableOffset, otl_LookupType lookupType, + const glyphid_t maxGlyphs, const otfcc_Options *options) { + switch (lookupType) { + LOOKUP_READER(otl_type_gsub_single, otl_read_gsub_single); + LOOKUP_READER(otl_type_gsub_multiple, otl_read_gsub_multi); + LOOKUP_READER(otl_type_gsub_alternate, otl_read_gsub_multi); + LOOKUP_READER(otl_type_gsub_ligature, otl_read_gsub_ligature); + LOOKUP_READER(otl_type_gsub_chaining, otl_read_chaining); + LOOKUP_READER(otl_type_gsub_reverse, otl_read_gsub_reverse); + LOOKUP_READER(otl_type_gpos_chaining, otl_read_chaining); + LOOKUP_READER(otl_type_gsub_context, otl_read_contextual); + LOOKUP_READER(otl_type_gpos_context, otl_read_contextual); + LOOKUP_READER(otl_type_gpos_single, otl_read_gpos_single); + LOOKUP_READER(otl_type_gpos_pair, otl_read_gpos_pair); + LOOKUP_READER(otl_type_gpos_cursive, otl_read_gpos_cursive); + LOOKUP_READER(otl_type_gpos_markToBase, otl_read_gpos_markToSingle); + LOOKUP_READER(otl_type_gpos_markToMark, otl_read_gpos_markToSingle); + LOOKUP_READER(otl_type_gpos_markToLigature, otl_read_gpos_markToLigature); + LOOKUP_READER(otl_type_gsub_extend, otfcc_readOtl_gsub_extend); + LOOKUP_READER(otl_type_gpos_extend, otfcc_readOtl_gpos_extend); + default: + return NULL; + } +} + +static void parseLanguage(font_file_pointer data, uint32_t tableLength, uint32_t base, + otl_LanguageSystem *lang, otl_FeatureList *features) { + checkLength(base + 6); + tableid_t rid = read_16u(data + base + 2); + if (rid < features->length) { + lang->requiredFeature = features->items[rid]; + } else { + lang->requiredFeature = NULL; + } + tableid_t featureCount = read_16u(data + base + 4); + for (tableid_t j = 0; j < featureCount; j++) { + tableid_t featureIndex = read_16u(data + base + 6 + 2 * j); + if (featureIndex < features->length) { + otl_iFeatureRefList.push(&lang->features, features->items[featureIndex]); + } + } + return; +FAIL: + otl_iFeatureRefList.dispose(&lang->features); + lang->requiredFeature = NULL; + return; +} + +static table_OTL *otfcc_readOtl_common(font_file_pointer data, uint32_t tableLength, + otl_LookupType lookup_type_base, + const otfcc_Options *options) { + table_OTL *table = table_iOTL.create(); + if (!table) goto FAIL; + checkLength(10); + uint32_t scriptListOffset = read_16u(data + 4); + checkLength(scriptListOffset + 2); + uint32_t featureListOffset = read_16u(data + 6); + checkLength(featureListOffset + 2); + uint32_t lookupListOffset = read_16u(data + 8); + checkLength(lookupListOffset + 2); + + // parse lookup list + { + tableid_t lookupCount = read_16u(data + lookupListOffset); + checkLength(lookupListOffset + 2 + lookupCount * 2); + for (tableid_t j = 0; j < lookupCount; j++) { + otl_Lookup *lookup; + otl_iLookupPtr.init(&lookup); + lookup->_offset = lookupListOffset + read_16u(data + lookupListOffset + 2 + 2 * j); + checkLength(lookup->_offset + 6); + lookup->type = read_16u(data + lookup->_offset) + lookup_type_base; + otl_iLookupList.push(&table->lookups, lookup); + } + } + + // parse feature list + { + tableid_t featureCount = read_16u(data + featureListOffset); + checkLength(featureListOffset + 2 + featureCount * 6); + tableid_t lnk = 0; + for (tableid_t j = 0; j < featureCount; j++) { + otl_Feature *feature; + otl_iFeaturePtr.init(&feature); + uint32_t tag = read_32u(data + featureListOffset + 2 + j * 6); + if (options->glyph_name_prefix) { + feature->name = sdscatprintf(sdsempty(), "%c%c%c%c_%s_%05d", (tag >> 24) & 0xFF, + (tag >> 16) & 0xFF, (tag >> 8) & 0xff, tag & 0xff, + options->glyph_name_prefix, j); + } else { + feature->name = sdscatprintf(sdsempty(), "%c%c%c%c_%05d", (tag >> 24) & 0xFF, + (tag >> 16) & 0xFF, (tag >> 8) & 0xff, tag & 0xff, j); + } + uint32_t featureOffset = + featureListOffset + read_16u(data + featureListOffset + 2 + j * 6 + 4); + + checkLength(featureOffset + 4); + tableid_t lookupCount = read_16u(data + featureOffset + 2); + checkLength(featureOffset + 4 + lookupCount * 2); + for (tableid_t k = 0; k < lookupCount; k++) { + tableid_t lookupid = read_16u(data + featureOffset + 4 + k * 2); + if (lookupid < table->lookups.length) { + otl_Lookup *lookup = table->lookups.items[lookupid]; + if (!lookup->name) { + if (options->glyph_name_prefix) { + lookup->name = sdscatprintf(sdsempty(), "lookup_%s_%c%c%c%c_%d", + options->glyph_name_prefix, + (tag >> 24) & 0xFF, (tag >> 16) & 0xFF, + (tag >> 8) & 0xff, tag & 0xff, lnk++); + } else { + lookup->name = sdscatprintf(sdsempty(), "lookup_%c%c%c%c_%d", + (tag >> 24) & 0xFF, (tag >> 16) & 0xFF, + (tag >> 8) & 0xff, tag & 0xff, lnk++); + } + } + otl_iLookupRefList.push(&feature->lookups, lookup); + } + } + otl_iFeatureList.push(&table->features, feature); + } + } + + // parse script list + { + tableid_t scriptCount = read_16u(data + scriptListOffset); + checkLength(scriptListOffset + 2 + 6 * scriptCount); + + uint32_t nLanguageCombinations = 0; + for (tableid_t j = 0; j < scriptCount; j++) { + uint32_t scriptOffset = + scriptListOffset + read_16u(data + scriptListOffset + 2 + 6 * j + 4); + checkLength(scriptOffset + 4); + + tableid_t defaultLangSystem = read_16u(data + scriptOffset); + nLanguageCombinations += + (defaultLangSystem ? 1 : 0) + read_16u(data + scriptOffset + 2); + } + + for (tableid_t j = 0; j < scriptCount; j++) { + uint32_t tag = read_32u(data + scriptListOffset + 2 + 6 * j); + uint32_t scriptOffset = + scriptListOffset + read_16u(data + scriptListOffset + 2 + 6 * j + 4); + tableid_t defaultLangSystem = read_16u(data + scriptOffset); + if (defaultLangSystem) { + otl_LanguageSystem *lang; + otl_iLanguageSystem.init(&lang); + lang->name = sdscatprintf(sdsempty(), "%c%c%c%c%cDFLT", (tag >> 24) & 0xFF, + (tag >> 16) & 0xFF, (tag >> 8) & 0xff, tag & 0xff, + SCRIPT_LANGUAGE_SEPARATOR); + parseLanguage(data, tableLength, scriptOffset + defaultLangSystem, lang, + &table->features); + otl_iLangSystemList.push(&table->languages, lang); + } + tableid_t langSysCount = read_16u(data + scriptOffset + 2); + for (tableid_t k = 0; k < langSysCount; k++) { + uint32_t langTag = read_32u(data + scriptOffset + 4 + 6 * k); + tableid_t langSys = read_16u(data + scriptOffset + 4 + 6 * k + 4); + otl_LanguageSystem *lang; + otl_iLanguageSystem.init(&lang); + lang->name = + sdscatprintf(sdsempty(), "%c%c%c%c%c%c%c%c%c", (tag >> 24) & 0xFF, + (tag >> 16) & 0xFF, (tag >> 8) & 0xff, tag & 0xff, + SCRIPT_LANGUAGE_SEPARATOR, (langTag >> 24) & 0xFF, + (langTag >> 16) & 0xFF, (langTag >> 8) & 0xff, langTag & 0xff); + parseLanguage(data, tableLength, scriptOffset + langSys, lang, &table->features); + otl_iLangSystemList.push(&table->languages, lang); + } + } + } + + // name all lookups + for (tableid_t j = 0; j < table->lookups.length; j++) { + if (!table->lookups.items[j]->name) { + if (options->glyph_name_prefix) { + table->lookups.items[j]->name = + sdscatprintf(sdsempty(), "lookup_%s_%02x_%d", options->glyph_name_prefix, + table->lookups.items[j]->type, j); + } else { + table->lookups.items[j]->name = + sdscatprintf(sdsempty(), "lookup_%02x_%d", table->lookups.items[j]->type, j); + } + } + } + return table; +FAIL: + if (table) table_iOTL.free(table); + return NULL; +} + +static void otfcc_readOtl_lookup(font_file_pointer data, uint32_t tableLength, otl_Lookup *lookup, + glyphid_t maxGlyphs, const otfcc_Options *options) { + lookup->flags = read_16u(data + lookup->_offset + 2); + tableid_t subtableCount = read_16u(data + lookup->_offset + 4); + if (!subtableCount || tableLength < lookup->_offset + 6 + 2 * subtableCount) { + lookup->type = otl_type_unknown; + return; + } + for (tableid_t j = 0; j < subtableCount; j++) { + uint32_t subtableOffset = lookup->_offset + read_16u(data + lookup->_offset + 6 + j * 2); + otl_Subtable *subtable = otfcc_readOtl_subtable(data, tableLength, subtableOffset, + lookup->type, maxGlyphs, options); + otl_iSubtableList.push(&lookup->subtables, subtable); + } + if (lookup->type == otl_type_gsub_extend || lookup->type == otl_type_gpos_extend) { + lookup->type = 0; + for (tableid_t j = 0; j < lookup->subtables.length; j++) { + if (lookup->subtables.items[j]) { + lookup->type = lookup->subtables.items[j]->extend.type; + break; + } + } + if (lookup->type) { + for (tableid_t j = 0; j < lookup->subtables.length; j++) { + if (lookup->subtables.items[j] && + lookup->subtables.items[j]->extend.type == lookup->type) { + // this subtable is valid + otl_Subtable *st = lookup->subtables.items[j]->extend.subtable; + FREE(lookup->subtables.items[j]); + lookup->subtables.items[j] = st; + } else if (lookup->subtables.items[j]) { + // type mismatch, delete this subtable + otl_Lookup *temp; + otl_iLookupPtr.init(&temp); + temp->type = lookup->subtables.items[j]->extend.type; + otl_iSubtableList.push(&temp->subtables, + lookup->subtables.items[j]->extend.subtable); + DELETE(otfcc_delete_lookup, temp); + FREE(lookup->subtables.items[j]); + } + } + } else { + otl_iSubtableList.disposeDependent(&lookup->subtables, lookup); + return; + } + } + if (lookup->type == otl_type_gsub_context) lookup->type = otl_type_gsub_chaining; + if (lookup->type == otl_type_gpos_context) lookup->type = otl_type_gpos_chaining; +} + +table_OTL *otfcc_readOtl(otfcc_Packet packet, const otfcc_Options *options, uint32_t tag, + glyphid_t maxGlyphs) { + table_OTL *otl = NULL; + FOR_TABLE(tag, table) { + font_file_pointer data = table.data; + uint32_t length = table.length; + otl = otfcc_readOtl_common(data, length, + (tag == OTFCC_CHR('G','S','U','B') + ? otl_type_gsub_unknown + : tag == OTFCC_CHR('G','P','O','S') ? otl_type_gpos_unknown : otl_type_unknown), + options); + if (!otl) goto FAIL; + for (tableid_t j = 0; j < otl->lookups.length; j++) { + otfcc_readOtl_lookup(data, length, otl->lookups.items[j], maxGlyphs, options); + } + return otl; + FAIL: + if (otl) table_iOTL.free(otl); + otl = NULL; + } + return NULL; +} |