diff options
Diffstat (limited to 'Build/source/texk/web2c/mfluadir/otfcc/lib/table/BASE.c')
-rw-r--r-- | Build/source/texk/web2c/mfluadir/otfcc/lib/table/BASE.c | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/lib/table/BASE.c b/Build/source/texk/web2c/mfluadir/otfcc/lib/table/BASE.c new file mode 100644 index 00000000000..bc42832cf65 --- /dev/null +++ b/Build/source/texk/web2c/mfluadir/otfcc/lib/table/BASE.c @@ -0,0 +1,330 @@ +#include "BASE.h" + +#include "otl/private.h" + + +static void deleteBaseAxis(MOVE otl_BaseAxis *axis) { + if (!axis) return; + if (axis->entries) { + for (tableid_t j = 0; j < axis->scriptCount; j++) { + if (axis->entries[j].baseValues) FREE(axis->entries[j].baseValues); + } + FREE(axis->entries); + } +} + +static INLINE void disposeBASE(MOVE table_BASE *base) { + deleteBaseAxis(base->horizontal); + deleteBaseAxis(base->vertical); +} + +caryll_standardRefType(table_BASE, table_iBASE, disposeBASE); + +static int16_t readBaseValue(font_file_pointer data, uint32_t tableLength, uint16_t offset) { + checkLength(offset + 4); + return read_16s(data + offset + 2); +FAIL: + return 0; +} + +static void readBaseScript(const font_file_pointer data, uint32_t tableLength, uint16_t offset, + otl_BaseScriptEntry *entry, uint32_t *baseTagList, uint16_t nBaseTags) { + entry->baseValuesCount = 0; + entry->baseValues = NULL; + entry->defaultBaselineTag = 0; + checkLength(offset + 2); // care about base values only now + uint16_t baseValuesOffset = read_16u(data + offset); + if (baseValuesOffset) { + baseValuesOffset += offset; + checkLength(baseValuesOffset + 4); + uint16_t defaultIndex = read_16u(data + baseValuesOffset) % nBaseTags; + entry->defaultBaselineTag = baseTagList[defaultIndex]; + entry->baseValuesCount = read_16u(data + baseValuesOffset + 2); + if (entry->baseValuesCount != nBaseTags) goto FAIL; + checkLength(baseValuesOffset + 4 + 2 * entry->baseValuesCount); + NEW(entry->baseValues, entry->baseValuesCount); + for (tableid_t j = 0; j < entry->baseValuesCount; j++) { + entry->baseValues[j].tag = baseTagList[j]; + uint16_t _valOffset = read_16u(data + baseValuesOffset + 4 + 2 * j); + if (_valOffset) { + entry->baseValues[j].coordinate = + readBaseValue(data, tableLength, baseValuesOffset + _valOffset); + } else { + entry->baseValues[j].coordinate = 0; + } + } + return; + } +FAIL: + entry->baseValuesCount = 0; + if (entry->baseValues) FREE(entry->baseValues); + entry->baseValues = NULL; + entry->defaultBaselineTag = 0; + return; +} + +static otl_BaseAxis *readAxis(font_file_pointer data, uint32_t tableLength, uint16_t offset) { + otl_BaseAxis *axis = NULL; + uint32_t *baseTagList = NULL; + checkLength(offset + 4); + + // Read BaseTagList + uint16_t baseTagListOffset = offset + read_16u(data + offset); + if (baseTagListOffset <= offset) goto FAIL; + checkLength(baseTagListOffset + 2); + uint16_t nBaseTags = read_16u(data + baseTagListOffset); + if (!nBaseTags) goto FAIL; + checkLength(baseTagListOffset + 2 + 4 * nBaseTags); + NEW(baseTagList, nBaseTags); + for (uint16_t j = 0; j < nBaseTags; j++) { + baseTagList[j] = read_32u(data + baseTagListOffset + 2 + j * 4); + } + + uint16_t baseScriptListOffset = offset + read_16u(data + offset + 2); + if (baseScriptListOffset <= offset) goto FAIL; + checkLength(baseScriptListOffset + 2); + tableid_t nBaseScripts = read_16u(data + baseScriptListOffset); + checkLength(baseScriptListOffset + 2 + 6 * nBaseScripts); + NEW(axis); + axis->scriptCount = nBaseScripts; + NEW(axis->entries, nBaseScripts); + for (tableid_t j = 0; j < nBaseScripts; j++) { + axis->entries[j].tag = read_32u(data + baseScriptListOffset + 2 + 6 * j); + uint16_t baseScriptOffset = read_16u(data + baseScriptListOffset + 2 + 6 * j + 4); + if (baseScriptOffset) { + readBaseScript(data, tableLength, baseScriptListOffset + baseScriptOffset, + &(axis->entries[j]), baseTagList, nBaseTags); + } else { + axis->entries[j].baseValuesCount = 0; + axis->entries[j].baseValues = NULL; + axis->entries[j].defaultBaselineTag = 0; + } + } + return axis; + +FAIL: + if (baseTagList) FREE(baseTagList); + DELETE(deleteBaseAxis, axis); + return axis; +} + +table_BASE *otfcc_readBASE(const otfcc_Packet packet, const otfcc_Options *options) { + table_BASE *base = NULL; + FOR_TABLE(OTFCC_CHR('B','A','S','E'), table) { + font_file_pointer data = table.data; + uint32_t tableLength = table.length; + checkLength(8); + NEW(base); + uint16_t offsetH = read_16u(data + 4); + if (offsetH) base->horizontal = readAxis(data, tableLength, offsetH); + uint16_t offsetV = read_16u(data + 6); + if (offsetV) base->vertical = readAxis(data, tableLength, offsetV); + return base; + FAIL: + logWarning("Table 'BASE' Corrupted"); + DELETE(table_iBASE.free, base); + } + return base; +} + +static json_value *axisToJson(const otl_BaseAxis *axis) { + json_value *_axis = json_object_new(axis->scriptCount); + for (tableid_t j = 0; j < axis->scriptCount; j++) { + if (!axis->entries[j].tag) continue; + json_value *_entry = json_object_new(3); + if (axis->entries[j].defaultBaselineTag) { + char tag[4]; + tag2str(axis->entries[j].defaultBaselineTag, tag); + json_object_push(_entry, "defaultBaseline", json_string_new_length(4, tag)); + } + json_value *_values = json_object_new(axis->entries[j].baseValuesCount); + for (tableid_t k = 0; k < axis->entries[j].baseValuesCount; k++) { + if (axis->entries[j].baseValues[k].tag) { + + json_object_push_tag(_values, axis->entries[j].baseValues[k].tag, + json_new_position(axis->entries[j].baseValues[k].coordinate)); + } + } + json_object_push(_entry, "baselines", _values); + json_object_push_tag(_axis, axis->entries[j].tag, _entry); + } + return _axis; +} + +void otfcc_dumpBASE(const table_BASE *base, json_value *root, const otfcc_Options *options) { + if (!base) return; + loggedStep("BASE") { + json_value *_base = json_object_new(2); + if (base->horizontal) json_object_push(_base, "horizontal", axisToJson(base->horizontal)); + if (base->vertical) json_object_push(_base, "vertical", axisToJson(base->vertical)); + json_object_push(root, "BASE", _base); + } +} + +static void baseScriptFromJson(const json_value *_sr, otl_BaseScriptEntry *entry) { + entry->defaultBaselineTag = str2tag(json_obj_getstr_share(_sr, "defaultBaseline")); + json_value *_basevalues = json_obj_get_type(_sr, "baselines", json_object); + if (!_basevalues) { + entry->baseValuesCount = 0; + entry->baseValues = NULL; + } else { + entry->baseValuesCount = _basevalues->u.object.length; + NEW(entry->baseValues, entry->baseValuesCount); + for (tableid_t j = 0; j < entry->baseValuesCount; j++) { + entry->baseValues[j].tag = str2tag(_basevalues->u.object.values[j].name); + entry->baseValues[j].coordinate = json_numof(_basevalues->u.object.values[j].value); + } + } +} + +static int by_script_tag(const void *a, const void *b) { + return ((const otl_BaseScriptEntry *)a)->tag - ((const otl_BaseScriptEntry *)b)->tag; +} + +static otl_BaseAxis *axisFromJson(const json_value *_axis) { + if (!_axis) return NULL; + otl_BaseAxis *axis; + NEW(axis); + axis->scriptCount = _axis->u.object.length; + NEW(axis->entries, axis->scriptCount); + tableid_t jj = 0; + for (tableid_t j = 0; j < axis->scriptCount; j++) { + if (_axis->u.object.values[j].value && + _axis->u.object.values[j].value->type == json_object) { + axis->entries[jj].tag = str2tag(_axis->u.object.values[j].name); + baseScriptFromJson(_axis->u.object.values[j].value, &(axis->entries[jj])); + jj++; + } + } + axis->scriptCount = jj; + qsort(axis->entries, axis->scriptCount, sizeof(otl_BaseScriptEntry), by_script_tag); + return axis; +} + +table_BASE *otfcc_parseBASE(const json_value *root, const otfcc_Options *options) { + table_BASE *base = NULL; + json_value *table = NULL; + if ((table = json_obj_get_type(root, "BASE", json_object))) { + loggedStep("BASE") { + NEW(base); + base->horizontal = axisFromJson(json_obj_get_type(table, "horizontal", json_object)); + base->vertical = axisFromJson(json_obj_get_type(table, "vertical", json_object)); + } + } + return base; +} + +static int by_tag(const void *a, const void *b) { + return *((const uint32_t *)a) - *((const uint32_t *)b); +} + +static bk_Block *axisToBk(const otl_BaseAxis *axis) { + if (!axis) return NULL; + struct { + tableid_t size; + uint32_t *items; + } taglist; + taglist.size = 0; + taglist.items = NULL; + + for (tableid_t j = 0; j < axis->scriptCount; j++) { + otl_BaseScriptEntry *entry = &(axis->entries[j]); + if (entry->defaultBaselineTag) { + bool found = false; + for (tableid_t jk = 0; jk < taglist.size; jk++) { + if (taglist.items[jk] == entry->defaultBaselineTag) { + found = true; + break; + } + } + if (!found) { + taglist.size += 1; + RESIZE(taglist.items, taglist.size); + taglist.items[taglist.size - 1] = entry->defaultBaselineTag; + } + } + for (tableid_t k = 0; k < entry->baseValuesCount; k++) { + uint32_t tag = entry->baseValues[k].tag; + bool found = false; + for (tableid_t jk = 0; jk < taglist.size; jk++) { + if (taglist.items[jk] == tag) { + found = true; + break; + } + } + if (!found) { + taglist.size += 1; + RESIZE(taglist.items, taglist.size); + taglist.items[taglist.size - 1] = tag; + } + } + } + qsort(taglist.items, taglist.size, sizeof(uint32_t), by_tag); + bk_Block *baseTagList = bk_new_Block(b16, taglist.size, bkover); + for (tableid_t j = 0; j < taglist.size; j++) { + bk_push(baseTagList, b32, taglist.items[j], bkover); + } + + bk_Block *baseScriptList = bk_new_Block(b16, axis->scriptCount, bkover); + for (tableid_t j = 0; j < axis->scriptCount; j++) { + otl_BaseScriptEntry *entry = &(axis->entries[j]); + bk_Block *baseValues = bk_new_Block(bkover); + { + tableid_t defaultIndex = 0; + for (tableid_t m = 0; m < taglist.size; m++) { + if (taglist.items[m] == entry->defaultBaselineTag) { + defaultIndex = m; + break; + } + } + bk_push(baseValues, b16, defaultIndex, bkover); + } + bk_push(baseValues, b16, taglist.size, bkover); + for (size_t m = 0; m < taglist.size; m++) { + bool found = false; + tableid_t foundIndex = 0; + for (tableid_t k = 0; k < entry->baseValuesCount; k++) { + if (entry->baseValues[k].tag == taglist.items[m]) { + found = true, foundIndex = k; + break; + } + } + if (found) { + bk_push(baseValues, // base value + p16, + bk_new_Block( + b16, 1, // format + b16, (int16_t)entry->baseValues[foundIndex].coordinate, // coordinate + bkover), + bkover); + } else { + bk_push(baseValues, // assign a zero value + p16, + bk_new_Block(b16, 1, // format + b16, 0, // coordinate + bkover), + bkover); + } + } + bk_Block *scriptRecord = bk_new_Block(p16, baseValues, // BaseValues + p16, NULL, // DefaultMinMax + b16, 0, // BaseLangSysCount + bkover); + bk_push(baseScriptList, b32, entry->tag, // BaseScriptTag + p16, scriptRecord, // BaseScript + bkover); + } + FREE(taglist.items); + return bk_new_Block(p16, baseTagList, // BaseTagList + p16, baseScriptList, // BaseScriptList + bkover); +} + +caryll_Buffer *otfcc_buildBASE(const table_BASE *base, const otfcc_Options *options) { + if (!base) return NULL; + bk_Block *root = bk_new_Block(b32, 0x10000, // Version + p16, axisToBk(base->horizontal), // HorizAxis + p16, axisToBk(base->vertical), // VertAxis + bkover); + return bk_build_Block(root); +} |