diff options
Diffstat (limited to 'Build/source/texk/web2c/mfluadir/otfcc/lib/table/CPAL.c')
-rw-r--r-- | Build/source/texk/web2c/mfluadir/otfcc/lib/table/CPAL.c | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/lib/table/CPAL.c b/Build/source/texk/web2c/mfluadir/otfcc/lib/table/CPAL.c new file mode 100644 index 00000000000..50131df6377 --- /dev/null +++ b/Build/source/texk/web2c/mfluadir/otfcc/lib/table/CPAL.c @@ -0,0 +1,280 @@ +#include "CPAL.h" + +#include "support/util.h" +#include "bk/bkgraph.h" + + +// Colors are trivial. +caryll_standardType(cpal_Color, cpal_iColor); +caryll_standardVectorImpl(cpal_ColorSet, cpal_Color, cpal_iColor, cpal_iColorSet); + +// Palettes are non-trivial. +static INLINE void initPalette(cpal_Palette *p) { + cpal_iColorSet.init(&p->colorset); + p->type = 0; + p->label = 0xFFFF; +} +static INLINE void disposePalette(cpal_Palette *p) { + cpal_iColorSet.dispose(&p->colorset); +} +caryll_standardType(cpal_Palette, cpal_iPalette, initPalette, disposePalette); +caryll_standardVectorImpl(cpal_PaletteSet, cpal_Palette, cpal_iPalette, cpal_iPaletteSet); + +// CPAL table +static INLINE void initCPAL(table_CPAL *cpal) { + cpal->version = 1; + cpal_iPaletteSet.init(&cpal->palettes); +} +static INLINE void disposeCPAL(table_CPAL *cpal) { + cpal_iPaletteSet.dispose(&cpal->palettes); +} +caryll_standardRefType(table_CPAL, table_iCPAL, initCPAL, disposeCPAL); + +const cpal_Color white = {.red = 0xFF, .green = 0xFF, .blue = 0xFF, .alpha = 0xFF, .label = 0xFFFF}; + +table_CPAL *otfcc_readCPAL(const otfcc_Packet packet, const otfcc_Options *options) { + table_CPAL *t = NULL; + FOR_TABLE(OTFCC_CHR('C','P','A','L'), table) { + font_file_pointer data = table.data; + uint32_t length = table.length; + if (length < 2) goto FAIL; + t = table_iCPAL.create(); + uint16_t version = read_16u(data); + uint32_t tableHeaderLength = (version == 0 ? 14 : 26); + if (length < tableHeaderLength) goto FAIL; + + t->version = version; + uint16_t numPalettesEntries = read_16u(data + 2); + uint16_t numPalettes = read_16u(data + 4); + uint16_t numColorRecords = read_16u(data + 6); + uint32_t offsetFirstColorRecord = read_32u(data + 8); + if (length < offsetFirstColorRecord + numColorRecords * 4) goto FAIL; + if (length < tableHeaderLength + 2 * numPalettes) goto FAIL; + + // read color list + cpal_Color *colorList; + NEW(colorList, numColorRecords); + for (uint16_t j = 0; j < numColorRecords; j++) { + colorList[j] = (cpal_Color){.blue = read_8u(data + offsetFirstColorRecord + j * 4), + .green = read_8u(data + offsetFirstColorRecord + j * 4 + 1), + .red = read_8u(data + offsetFirstColorRecord + j * 4 + 2), + .alpha = read_8u(data + offsetFirstColorRecord + j * 4 + 3), + .label = 0xFFFF}; + } + + // read palettes + for (tableid_t j = 0; j < numPalettes; j++) { + cpal_Palette palette; + cpal_iPalette.init(&palette); + tableid_t paletteStartIndex = read_16u(data + 12 + j * 2); + for (colorid_t j = 0; j < numPalettesEntries; j++) { + if (paletteStartIndex + j < numColorRecords) { + cpal_iColorSet.push(&palette.colorset, colorList[j + paletteStartIndex]); + } else { + cpal_iColorSet.push(&palette.colorset, white); + } + } + cpal_iPaletteSet.push(&t->palettes, palette); + } + + if (version > 0) { + uint32_t offsetPaletteTypeArray = read_32u(data + 16 + 2 * numPalettes); + if (offsetPaletteTypeArray && length >= offsetPaletteTypeArray + 4 * numPalettes) { + for (tableid_t j = 0; j < numPalettes; j++) { + uint32_t type = read_32u(data + j * 4 + offsetPaletteTypeArray); + t->palettes.items[j].type = type; + } + } + uint32_t offsetPaletteLabelArray = read_32u(data + 20 + 2 * numPalettes); + if (offsetPaletteLabelArray && length >= offsetPaletteLabelArray + 2 * numPalettes) { + for (tableid_t j = 0; j < numPalettes; j++) { + uint16_t label = read_16u(data + j * 2 + offsetPaletteLabelArray); + t->palettes.items[j].label = label; + } + } + + if (version > 0) { + uint32_t offsetPaletteEntryLabelArray = read_32u(data + 24 + 2 * numPalettes); + if (offsetPaletteEntryLabelArray && + length >= offsetPaletteEntryLabelArray + 4 * numPalettesEntries) { + for (colorid_t j = 0; j < numPalettesEntries; j++) { + uint16_t label = read_16u(data + j * 2 + offsetPaletteEntryLabelArray); + for (tableid_t k = 0; k < numPalettes; k++) { + t->palettes.items[k].colorset.items[j].label = label; + } + } + } + } + } + + FREE(colorList); + return t; + + FAIL: + table_iCPAL.free(t); + t = NULL; + } + return NULL; +} + +static INLINE json_value *dumpColor(cpal_Color *color) { + json_value *_color = json_object_new(5); + json_object_push(_color, "red", json_integer_new(color->red)); + json_object_push(_color, "green", json_integer_new(color->green)); + json_object_push(_color, "blue", json_integer_new(color->blue)); + if (color->alpha != 0xFF) json_object_push(_color, "alpha", json_integer_new(color->alpha)); + if (color->label != 0xFFFF) json_object_push(_color, "label", json_integer_new(color->label)); + return preserialize(_color); +} + +static INLINE json_value *dumpPalette(cpal_Palette *palette) { + json_value *_palette = json_object_new(3); + if (palette->type) { json_object_push(_palette, "type", json_integer_new(palette->type)); } + if (palette->label != 0xFFFF) { + json_object_push(_palette, "label", json_integer_new(palette->label)); + } + json_value *a = json_array_new(palette->colorset.length); + for (colorid_t j = 0; j < palette->colorset.length; j++) { + json_array_push(a, dumpColor(&palette->colorset.items[j])); + } + json_object_push(_palette, "colors", a); + return _palette; +} + +void otfcc_dumpCPAL(const table_CPAL *table, json_value *root, const otfcc_Options *options) { + if (!table) return; + loggedStep("CPAL") { + json_value *_t = json_object_new(2); + json_object_push(_t, "version", json_integer_new(table->version)); + json_value *_a = json_array_new(table->palettes.length); + for (tableid_t j = 0; j < table->palettes.length; j++) { + json_array_push(_a, dumpPalette(&table->palettes.items[j])); + } + json_object_push(_t, "palettes", _a); + json_object_push(root, "CPAL", _t); + } +} + +static INLINE cpal_Color parseColor(const json_value *_color) { + cpal_Color color = white; + if (!_color || _color->type != json_object) return color; + color.red = json_obj_getint_fallback(_color, "red", 0); + color.green = json_obj_getint_fallback(_color, "green", 0); + color.blue = json_obj_getint_fallback(_color, "blue", 0); + color.alpha = json_obj_getint_fallback(_color, "alpha", 0xFF); + color.label = json_obj_getint_fallback(_color, "label", 0xFFFF); + return color; +} + +table_CPAL *otfcc_parseCPAL(const json_value *root, const otfcc_Options *options) { + json_value *table = NULL; + if (!(table = json_obj_get_type(root, "CPAL", json_object))) return NULL; + table_CPAL *cpal = NULL; + loggedStep("CPAL") { + json_value *_palettes = json_obj_get_type(table, "palettes", json_array); + if (!_palettes || !_palettes->u.array.length) return NULL; + cpal = table_iCPAL.create(); + cpal->version = json_obj_getint(table, "version"); + for (tableid_t j = 0; j < _palettes->u.array.length; j++) { + json_value *_palette = _palettes->u.array.values[j]; + if (!_palette || _palette->type != json_object) continue; + json_value *_colors = json_obj_get_type(_palette, "colors", json_array); + if (!_colors) continue; + + // palette parser + cpal_Palette palette; + cpal_iPalette.init(&palette); + palette.type = json_obj_getint(_palette, "type"); + palette.label = json_obj_getint_fallback(_palette, "type", 0xFFFF); + + // color list parser + for (colorid_t k = 0; k < _colors->u.array.length; k++) { + cpal_iColorSet.push(&palette.colorset, parseColor(_colors->u.array.values[k])); + } + + // push into cpal + cpal_iPaletteSet.push(&cpal->palettes, palette); + } + } + return cpal; +} + +static INLINE bk_Block *buildPaletteType(const table_CPAL *cpal) { + bool needsPaletteType = false; + for (tableid_t j = 0; j < cpal->palettes.length; j++) { + if (cpal->palettes.items[j].type) needsPaletteType = true; + } + if (!needsPaletteType) return NULL; + bk_Block *block = bk_new_Block(bkover); + for (tableid_t j = 0; j < cpal->palettes.length; j++) { + bk_push(block, b32, cpal->palettes.items[j].type, bkover); + } + return block; +} +static INLINE bk_Block *buildPaletteLabel(const table_CPAL *cpal) { + bool needsPaletteLabel = false; + for (tableid_t j = 0; j < cpal->palettes.length; j++) { + if (cpal->palettes.items[j].label != 0xFFFF) needsPaletteLabel = true; + } + if (!needsPaletteLabel) return NULL; + bk_Block *block = bk_new_Block(bkover); + for (tableid_t j = 0; j < cpal->palettes.length; j++) { + bk_push(block, b16, cpal->palettes.items[j].label, bkover); + } + return block; +} +static INLINE bk_Block *buildPaletteEntryLabel(const table_CPAL *cpal) { + bool needsPaletteEntryLabel = false; + cpal_Palette *palette = &cpal->palettes.items[0]; + for (colorid_t j = 0; j < palette->colorset.length; j++) { + if (palette->colorset.items[j].label != 0xFFFF) needsPaletteEntryLabel = true; + } + if (!needsPaletteEntryLabel) return NULL; + bk_Block *block = bk_new_Block(bkover); + for (colorid_t j = 0; j < palette->colorset.length; j++) { + bk_push(block, b16, palette->colorset.items[j].label, bkover); + } + return block; +} +caryll_Buffer *otfcc_buildCPAL(const table_CPAL *cpal, const otfcc_Options *options) { + if (!cpal || !cpal->palettes.length) return NULL; + uint16_t numPalettes = cpal->palettes.length; + uint16_t numPalettesEntries = cpal->palettes.items[0].colorset.length; + uint16_t numColorRecords = numPalettes * numPalettesEntries; + + bk_Block *colorRecords = bk_new_Block(bkover); + for (tableid_t j = 0; j < numPalettes; j++) { + cpal_Palette *palette = &cpal->palettes.items[j]; + colorid_t totalColors = palette->colorset.length; + for (colorid_t k = 0; k < numPalettesEntries; k++) { + const cpal_Color *color = NULL; + if (k < totalColors) { + color = &palette->colorset.items[k]; + } else { + color = &white; + } + bk_push(colorRecords, b8, color->blue, // blue + b8, color->green, // green + b8, color->red, // red + b8, color->alpha, // alpha + bkover); + } + } + + bk_Block *root = bk_new_Block(b16, cpal->version, // Version + b16, numPalettesEntries, // numPalettesEntries + b16, numPalettes, // numPalettes + b16, numColorRecords, // numColorRecords + p32, colorRecords, // offsetFirstColorRecord + bkover); + for (tableid_t j = 0; j < numPalettes; j++) { + bk_push(root, b16, numPalettesEntries * j, bkover); // colorRecordIndices + } + if (cpal->version > 0) { + bk_push(root, p32, buildPaletteType(cpal), // offsetPaletteTypeArray + p32, buildPaletteLabel(cpal), // offsetPaletteLabelArray + p32, buildPaletteEntryLabel(cpal), // offsetPaletteEntryLabelArray + bkover); + } + return bk_build_Block(root); +} |