diff options
Diffstat (limited to 'Build/source/texk/web2c/mfluadir/otfcc/lib/font/caryll-sfnt-builder.c')
-rw-r--r-- | Build/source/texk/web2c/mfluadir/otfcc/lib/font/caryll-sfnt-builder.c | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/lib/font/caryll-sfnt-builder.c b/Build/source/texk/web2c/mfluadir/otfcc/lib/font/caryll-sfnt-builder.c new file mode 100644 index 00000000000..8e6ff87030f --- /dev/null +++ b/Build/source/texk/web2c/mfluadir/otfcc/lib/font/caryll-sfnt-builder.c @@ -0,0 +1,115 @@ +#include "support/util.h" +#include "otfcc/sfnt-builder.h" + +#define OTFCC_CHR(a,b,c,d) ( ((a)<<24) | ((b)<<16) | ((c)<<8) | (d) ) + +static uint32_t buf_checksum(caryll_Buffer *buffer) { + uint32_t actualLength = (uint32_t)buflen(buffer); + buflongalign(buffer); + uint32_t sum = 0; + { + uint32_t *start = (uint32_t *)buffer->data; + uint32_t *end = start + ((actualLength + 3) & ~3) / sizeof(uint32_t); + while (start < end) { + sum += otfcc_endian_convert32(*start++); + } + } + return sum; +} + +static otfcc_SFNTTableEntry *createSegment(uint32_t tag, caryll_Buffer *buffer) { + otfcc_SFNTTableEntry *table; + NEW(table); + table->tag = tag; + table->length = (uint32_t)buflen(buffer); + buflongalign(buffer); + table->buffer = buffer; + + uint32_t sum = 0; + { + uint32_t *start = (uint32_t *)buffer->data; + uint32_t *end = start + ((table->length + 3) & ~3) / sizeof(uint32_t); + while (start < end) { + sum += otfcc_endian_convert32(*start++); + } + } + table->checksum = sum; + return table; +} + +otfcc_SFNTBuilder *otfcc_newSFNTBuilder(uint32_t header, const otfcc_Options *options) { + otfcc_SFNTBuilder *builder; + NEW(builder); + builder->count = 0; + builder->header = header; + builder->tables = NULL; + builder->options = options; + return builder; +} + +void otfcc_deleteSFNTBuilder(otfcc_SFNTBuilder *builder) { + if (!builder) return; + otfcc_SFNTTableEntry *item, *tmp; + HASH_ITER(hh, builder->tables, item, tmp) { + HASH_DEL(builder->tables, item); + buffree(item->buffer); + FREE(item); + } + FREE(builder); +} + +void otfcc_SFNTBuilder_pushTable(otfcc_SFNTBuilder *builder, uint32_t tag, caryll_Buffer *buffer) { + if (!builder || !buffer) return; + otfcc_SFNTTableEntry *item; + const otfcc_Options *options = builder->options; + HASH_FIND_INT(builder->tables, &tag, item); + if (!item) { + item = createSegment(tag, buffer); + HASH_ADD_INT(builder->tables, tag, item); + logProgress("OpenType table %c%c%c%c successfully built.\n", (tag >> 24) & 0xff, + (tag >> 16) & 0xff, (tag >> 8) & 0xff, tag & 0xff); + } else { + buffree(buffer); + } +} + +static int byTag(otfcc_SFNTTableEntry *a, otfcc_SFNTTableEntry *b) { + return (a->tag - b->tag); +} + +caryll_Buffer *otfcc_SFNTBuilder_serialize(otfcc_SFNTBuilder *builder) { + caryll_Buffer *buffer = bufnew(); + if (!builder) return buffer; + uint16_t nTables = HASH_COUNT(builder->tables); + uint16_t searchRange = (nTables < 16 ? 8 : nTables < 32 ? 16 : nTables < 64 ? 32 : 64) * 16; + bufwrite32b(buffer, builder->header); + bufwrite16b(buffer, nTables); + bufwrite16b(buffer, searchRange); + bufwrite16b(buffer, (nTables < 16 ? 3 : nTables < 32 ? 4 : nTables < 64 ? 5 : 6)); + bufwrite16b(buffer, nTables * 16 - searchRange); + + otfcc_SFNTTableEntry *table; + size_t offset = 12 + nTables * 16; + size_t headOffset = offset; + HASH_SORT(builder->tables, byTag); + foreach_hash(table, builder->tables) { + // write table directory + bufwrite32b(buffer, table->tag); + bufwrite32b(buffer, table->checksum); + bufwrite32b(buffer, (uint32_t)offset); + bufwrite32b(buffer, table->length); + size_t cp = buffer->cursor; + bufseek(buffer, offset); + bufwrite_buf(buffer, table->buffer); + bufseek(buffer, cp); + // record where the [head] is + if (table->tag == OTFCC_CHR('h','e','a','d')) { headOffset = offset; } + offset += buflen(table->buffer); + } + + // write head.checksumAdjust + uint32_t wholeChecksum = buf_checksum(buffer); + bufseek(buffer, headOffset + 8); + bufwrite32b(buffer, 0xB1B0AFBA - wholeChecksum); + return buffer; +} |