summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/mfluadir/otfcc/lib/table/BASE.c
diff options
context:
space:
mode:
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.c330
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);
+}