diff options
Diffstat (limited to 'Build/source/texk/web2c/mfluadir/otfcc/lib/table/COLR.c')
-rw-r--r-- | Build/source/texk/web2c/mfluadir/otfcc/lib/table/COLR.c | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/lib/table/COLR.c b/Build/source/texk/web2c/mfluadir/otfcc/lib/table/COLR.c new file mode 100644 index 00000000000..6f82b5296b3 --- /dev/null +++ b/Build/source/texk/web2c/mfluadir/otfcc/lib/table/COLR.c @@ -0,0 +1,184 @@ +#include "COLR.h" + +#include "support/util.h" +#include "bk/bkgraph.h" + + +static INLINE void initLayer(colr_Layer *layer) { + Handle.init(&layer->glyph); +} +static INLINE void copyLayer(colr_Layer *dst, const colr_Layer *src) { + Handle.copy(&dst->glyph, &src->glyph); + dst->paletteIndex = src->paletteIndex; +} +static INLINE void disposeLayer(colr_Layer *layer) { + Handle.dispose(&layer->glyph); +} +caryll_standardType(colr_Layer, colr_iLayer, initLayer, copyLayer, disposeLayer); +caryll_standardVectorImpl(colr_LayerList, colr_Layer, colr_iLayer, colr_iLayerList); + +static INLINE void initMapping(colr_Mapping *mapping) { + Handle.init(&mapping->glyph); + colr_iLayerList.init(&mapping->layers); +} +static INLINE void copyMapping(colr_Mapping *dst, const colr_Mapping *src) { + Handle.copy(&dst->glyph, &src->glyph); + colr_iLayerList.copy(&dst->layers, &src->layers); +} +static INLINE void disposeMapping(colr_Mapping *mapping) { + Handle.dispose(&mapping->glyph); + colr_iLayerList.dispose(&mapping->layers); +} +caryll_standardType(colr_Mapping, colr_iMapping, initMapping, copyMapping, disposeMapping); +caryll_standardVectorImpl(table_COLR, colr_Mapping, colr_iMapping, table_iCOLR); + +static const size_t baseGlyphRecLength = 6; +static const size_t layerRecLength = 4; + +table_COLR *otfcc_readCOLR(const otfcc_Packet packet, const otfcc_Options *options) { + table_COLR *colr = NULL; + FOR_TABLE(OTFCC_CHR('C','O','L','R'), table) { + if (table.length < 14) goto FAIL; + uint16_t numBaseGlyphRecords = read_16u(table.data + 2); + uint16_t numLayerRecords = read_16u(table.data + 12); + uint32_t offsetBaseGlyphRecord = read_32u(table.data + 4); + uint32_t offsetLayerRecord = read_32u(table.data + 8); + if (table.length < offsetBaseGlyphRecord + baseGlyphRecLength * numBaseGlyphRecords) + goto FAIL; + if (table.length < offsetLayerRecord + layerRecLength * numLayerRecords) goto FAIL; + + // parse layer data + glyphid_t *gids; + colorid_t *colors; + NEW(gids, numLayerRecords); + NEW(colors, numLayerRecords); + for (glyphid_t j = 0; j < numLayerRecords; j++) { + gids[j] = read_16u(table.data + offsetLayerRecord + layerRecLength * j); + colors[j] = read_16u(table.data + offsetLayerRecord + layerRecLength * j + 2); + } + // parse decomposition data + colr = table_iCOLR.create(); + for (glyphid_t j = 0; j < numBaseGlyphRecords; j++) { + colr_Mapping mapping; + colr_iMapping.init(&mapping); + uint16_t gid = read_16u(table.data + offsetBaseGlyphRecord + baseGlyphRecLength * j); + uint16_t firstLayerIndex = + read_16u(table.data + offsetBaseGlyphRecord + baseGlyphRecLength * j + 2); + uint16_t numLayers = + read_16u(table.data + offsetBaseGlyphRecord + baseGlyphRecLength * j + 4); + + glyph_handle baseGlyph = Handle.fromIndex(gid); + Handle.move(&mapping.glyph, &baseGlyph); + for (glyphid_t k = 0; k < numLayers; k++) { + if (k + firstLayerIndex < numLayerRecords) { + colr_iLayerList.push(&mapping.layers, + (colr_Layer){ + .glyph = Handle.fromIndex(gids[k + firstLayerIndex]), + .paletteIndex = colors[k + firstLayerIndex], + }); + } + } + table_iCOLR.push(colr, mapping); + } + return colr; + FAIL: + logWarning("Table 'COLR' corrupted.\n"); + table_iCOLR.free(colr); + colr = NULL; + } + return colr; +} + +void otfcc_dumpCOLR(const table_COLR *colr, json_value *root, const otfcc_Options *options) { + if (!colr) return; + loggedStep("COLR") { + json_value *_colr = json_array_new(colr->length); + foreach (colr_Mapping *mapping, *colr) { + json_value *_map = json_object_new(2); + json_object_push(_map, "from", json_string_new(mapping->glyph.name)); + json_value *_layers = json_array_new(mapping->layers.length); + foreach (colr_Layer *layer, mapping->layers) { + json_value *_layer = json_object_new(2); + json_object_push(_layer, "layer", json_string_new(layer->glyph.name)); + json_object_push(_layer, "paletteIndex", json_integer_new(layer->paletteIndex)); + json_array_push(_layers, _layer); + } + json_object_push(_map, "to", preserialize(_layers)); + json_array_push(_colr, _map); + } + json_object_push(root, "COLR", _colr); + } +} + +table_COLR *otfcc_parseCOLR(const json_value *root, const otfcc_Options *options) { + json_value *_colr = NULL; + if (!(_colr = json_obj_get_type(root, "COLR", json_array))) return NULL; + table_COLR *colr = table_iCOLR.create(); + loggedStep("COLR") { + for (glyphid_t j = 0; j < _colr->u.array.length; j++) { + json_value *_mapping = _colr->u.array.values[j]; + if (!_mapping || _mapping->type != json_object) continue; + json_value *_baseglyph = json_obj_get_type(_mapping, "from", json_string); + json_value *_layers = json_obj_get_type(_mapping, "to", json_array); + if (!_baseglyph || !_layers) continue; + + colr_Mapping m; + colr_iMapping.init(&m); + m.glyph = + Handle.fromName(sdsnewlen(_baseglyph->u.string.ptr, _baseglyph->u.string.length)); + for (glyphid_t k = 0; k < _layers->u.array.length; k++) { + json_value *_layer = _layers->u.array.values[k]; + if (!_layer || _layer->type != json_object) continue; + json_value *_layerglyph = json_obj_get_type(_layer, "layer", json_string); + if (!_layerglyph) continue; + colr_iLayerList.push( + &m.layers, + (colr_Layer){ + .glyph = Handle.fromName( + sdsnewlen(_layerglyph->u.string.ptr, _layerglyph->u.string.length)), + .paletteIndex = json_obj_getint_fallback(_layer, "paletteIndex", 0xFFFF), + }); + } + table_iCOLR.push(colr, m); + } + } + return colr; +} + +static int byGID(const colr_Mapping *a, const colr_Mapping *b) { + return a->glyph.index - b->glyph.index; +} + +caryll_Buffer *otfcc_buildCOLR(const table_COLR *_colr, const otfcc_Options *options) { + if (!_colr || !_colr->length) return NULL; + + // sort base defs + table_COLR colr; + table_iCOLR.copy(&colr, _colr); + table_iCOLR.sort(&colr, byGID); + + glyphid_t currentLayerIndex = 0; + bk_Block *layerRecords = bk_new_Block(bkover); + bk_Block *baseRecords = bk_new_Block(bkover); + foreach (colr_Mapping *mapping, colr) { + bk_push(baseRecords, b16, mapping->glyph.index, // GID + b16, currentLayerIndex, // firstLayerIndex + b16, mapping->layers.length, // numLayers + bkover); + foreach (colr_Layer *layer, mapping->layers) { + bk_push(layerRecords, b16, layer->glyph.index, // GID + b16, layer->paletteIndex, // paletteIndex + bkover); + currentLayerIndex += 1; + } + } + + bk_Block *root = bk_new_Block(b16, 0, // Version + b16, colr.length, // numBaseGlyphRecords + p32, baseRecords, // offsetBaseGlyphRecord + p32, layerRecords, // offsetLayerRecord + b16, currentLayerIndex, // numLayerRecords + bkover); + table_iCOLR.dispose(&colr); + return bk_build_Block(root); +} |