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