diff --git a/lib/font/caryll-font.c b/lib/font/caryll-font.c index 6eec58f8..78daebc9 100644 --- a/lib/font/caryll-font.c +++ b/lib/font/caryll-font.c @@ -170,42 +170,52 @@ caryll_buffer *caryll_write_font(caryll_font *font, caryll_dump_options *dumpopt caryll_buffer *bufglyf = bufnew(); caryll_buffer *bufloca = bufnew(); if (font->glyf && font->head) { - caryll_write_glyf(font->glyf, font->head, bufglyf, bufloca); + caryll_write_glyf(font->glyf, font->head, bufglyf, bufloca, dumpopts); } sfnt_builder_push_table(builder, 'loca', bufloca); sfnt_builder_push_table(builder, 'glyf', bufglyf); } else { caryll_cff_parse_result r = {font->CFF_, font->glyf}; - sfnt_builder_push_table(builder, 'CFF ', caryll_write_CFF(r)); + sfnt_builder_push_table(builder, 'CFF ', caryll_write_CFF(r, dumpopts)); } - sfnt_builder_push_table(builder, 'head', caryll_write_head(font->head)); - sfnt_builder_push_table(builder, 'hhea', caryll_write_hhea(font->hhea)); - sfnt_builder_push_table(builder, 'OS/2', caryll_write_OS_2(font->OS_2)); - sfnt_builder_push_table(builder, 'maxp', caryll_write_maxp(font->maxp)); - sfnt_builder_push_table(builder, 'name', caryll_write_name(font->name)); - sfnt_builder_push_table(builder, 'post', caryll_write_post(font->post, font->glyph_order)); - sfnt_builder_push_table(builder, 'cmap', caryll_write_cmap(font->cmap)); - if (font->fpgm) sfnt_builder_push_table(builder, 'fpgm', caryll_write_fpgm_prep(font->fpgm)); - if (font->prep) sfnt_builder_push_table(builder, 'prep', caryll_write_fpgm_prep(font->prep)); - if (font->cvt_) sfnt_builder_push_table(builder, 'cvt ', caryll_write_cvt(font->cvt_)); - if (font->gasp) sfnt_builder_push_table(builder, 'gasp', caryll_write_gasp(font->gasp)); + sfnt_builder_push_table(builder, 'head', caryll_write_head(font->head, dumpopts)); + sfnt_builder_push_table(builder, 'hhea', caryll_write_hhea(font->hhea, dumpopts)); + sfnt_builder_push_table(builder, 'OS/2', caryll_write_OS_2(font->OS_2, dumpopts)); + sfnt_builder_push_table(builder, 'maxp', caryll_write_maxp(font->maxp, dumpopts)); + sfnt_builder_push_table(builder, 'name', caryll_write_name(font->name, dumpopts)); + sfnt_builder_push_table(builder, 'post', + caryll_write_post(font->post, font->glyph_order, dumpopts)); + sfnt_builder_push_table(builder, 'cmap', caryll_write_cmap(font->cmap, dumpopts)); + if (font->fpgm) + sfnt_builder_push_table(builder, 'fpgm', caryll_write_fpgm_prep(font->fpgm, dumpopts)); + if (font->prep) + sfnt_builder_push_table(builder, 'prep', caryll_write_fpgm_prep(font->prep, dumpopts)); + if (font->cvt_) + sfnt_builder_push_table(builder, 'cvt ', caryll_write_cvt(font->cvt_, dumpopts)); + if (font->gasp) + sfnt_builder_push_table(builder, 'gasp', caryll_write_gasp(font->gasp, dumpopts)); sfnt_builder_push_table(builder, 'hmtx', caryll_write_hmtx(font->hmtx, font->hhea->numberOfMetrics, - font->maxp->numGlyphs - font->hhea->numberOfMetrics)); + font->maxp->numGlyphs - font->hhea->numberOfMetrics, + dumpopts)); - if (font->vhea) sfnt_builder_push_table(builder, 'vhea', caryll_write_vhea(font->vhea)); + if (font->vhea) + sfnt_builder_push_table(builder, 'vhea', caryll_write_vhea(font->vhea, dumpopts)); if (font->vmtx) { sfnt_builder_push_table( builder, 'vmtx', caryll_write_vmtx(font->vmtx, font->vhea->numOfLongVerMetrics, - font->maxp->numGlyphs - font->vhea->numOfLongVerMetrics)); + font->maxp->numGlyphs - font->vhea->numOfLongVerMetrics, dumpopts)); } - if (font->GSUB) sfnt_builder_push_table(builder, 'GSUB', caryll_write_otl(font->GSUB)); - if (font->GPOS) sfnt_builder_push_table(builder, 'GPOS', caryll_write_otl(font->GPOS)); - if (font->GDEF) sfnt_builder_push_table(builder, 'GDEF', caryll_write_GDEF(font->GDEF)); + if (font->GSUB) + sfnt_builder_push_table(builder, 'GSUB', caryll_write_otl(font->GSUB, dumpopts)); + if (font->GPOS) + sfnt_builder_push_table(builder, 'GPOS', caryll_write_otl(font->GPOS, dumpopts)); + if (font->GDEF) + sfnt_builder_push_table(builder, 'GDEF', caryll_write_GDEF(font->GDEF, dumpopts)); if (dumpopts->dummy_DSIG) { caryll_buffer *dsig = bufnew(); diff --git a/lib/fontops/otl/chaining.c b/lib/fontops/otl/chaining.c index 48b6a75f..3799f3ae 100644 --- a/lib/fontops/otl/chaining.c +++ b/lib/fontops/otl/chaining.c @@ -214,10 +214,6 @@ void classify_around(otl_lookup *lookup, uint16_t j) { } endcheck: if (compatibleCount > 1) { - fprintf(stderr, "[Autoclassifier] %d subtables in %s are " - "class-compatible to subtable %d.", - compatibleCount, lookup->name, j); - fprintf(stderr, " Class count : B%d I%d F%d.\n", classno_b, classno_i, classno_f); compatibility[j] = true; free(subtable0->rules); NEW_N(subtable0->rules, compatibleCount + 1); diff --git a/lib/libcff/cff-charset.c b/lib/libcff/cff-charset.c new file mode 100644 index 00000000..f212c2ef --- /dev/null +++ b/lib/libcff/cff-charset.c @@ -0,0 +1,127 @@ +#include "cff-charset.h" + +void parse_charset(uint8_t *data, int32_t offset, uint16_t nchars, CFF_Charset *charsets) { + uint32_t i; + if (offset == CFF_CHARSET_ISOADOBE) + charsets->t = CFF_CHARSET_ISOADOBE; + else if (offset == CFF_CHARSET_EXPERT) + charsets->t = CFF_CHARSET_EXPERT; + else if (offset == CFF_CHARSET_EXPERTSUBSET) + charsets->t = CFF_CHARSET_EXPERTSUBSET; + else { + // NOTE: gid 1 will always be named as .notdef + switch (data[offset]) { + case 0: + charsets->t = CFF_CHARSET_FORMAT0; + { + charsets->s = nchars - 1; + charsets->f0.glyph = calloc(nchars - 1, sizeof(uint16_t)); + + for (i = 0; i < charsets->s; i++) + charsets->f0.glyph[i] = gu2(data, offset + 1 + i * 2); + } + break; + case 1: + charsets->t = CFF_CHARSET_FORMAT1; + { + uint32_t size; + uint32_t glyphsEncodedSofar = 1; + for (i = 0; glyphsEncodedSofar < nchars; i++) { + glyphsEncodedSofar += 1 + gu1(data, offset + 3 + i * 3); + } + + size = i; + charsets->s = size; + charsets->f1.range1 = calloc(i + 1, sizeof(charset_range1)); + for (i = 0; i < size; i++) { + charsets->f1.range1[i].first = gu2(data, offset + 1 + i * 3); + charsets->f1.range1[i].nleft = gu1(data, offset + 3 + i * 3); + } + } + break; + case 2: + charsets->t = CFF_CHARSET_FORMAT2; + { + uint32_t size; + uint32_t glyphsEncodedSofar = 1; + for (i = 0; glyphsEncodedSofar < nchars; i++) { + glyphsEncodedSofar += 1 + gu2(data, offset + 3 + i * 4); + } + + size = i; + charsets->s = size; + charsets->f2.range2 = calloc(i + 1, sizeof(charset_range2)); + + for (i = 0; i < size; i++) { + charsets->f2.range2[i].first = gu2(data, offset + 1 + i * 4); + charsets->f2.range2[i].nleft = gu2(data, offset + 3 + i * 4); + } + } + break; + } + } +} + +caryll_buffer *compile_charset(CFF_Charset cset) { + switch (cset.t) { + case CFF_CHARSET_ISOADOBE: + case CFF_CHARSET_EXPERT: + case CFF_CHARSET_EXPERTSUBSET: { + return bufnew(); + } + case CFF_CHARSET_FORMAT0: { + caryll_buffer *blob = bufnew(); + blob->size = 1 + cset.s * 2; + blob->data = calloc(blob->size, sizeof(uint8_t)); + blob->data[0] = 0; + for (uint32_t i = 0; i < cset.s; i++) + blob->data[1 + 2 * i] = cset.f0.glyph[i] / 256, + blob->data[2 + 2 * i] = cset.f0.glyph[i] % 256; + blob->cursor = blob->size; + return blob; + } + case CFF_CHARSET_FORMAT1: { + caryll_buffer *blob = bufnew(); + blob->size = 1 + cset.s * 3; + blob->data = calloc(blob->size, sizeof(uint8_t)); + blob->data[0] = 1; + for (uint32_t i = 0; i < cset.s; i++) + blob->data[1 + 3 * i] = cset.f1.range1[i].first / 256, + blob->data[2 + 3 * i] = cset.f1.range1[i].first % 256, + blob->data[3 + 3 * i] = cset.f1.range1[i].nleft; + return blob; + } + case CFF_CHARSET_FORMAT2: { + caryll_buffer *blob = bufnew(); + blob->size = 1 + cset.s * 4; + blob->data = calloc(blob->size, sizeof(uint8_t)); + blob->data[0] = 2; + for (uint32_t i = 0; i < cset.s; i++) + blob->data[1 + 4 * i] = cset.f2.range2[i].first / 256, + blob->data[2 + 4 * i] = cset.f2.range2[i].first % 256, + blob->data[3 + 4 * i] = cset.f2.range2[i].nleft / 256, + blob->data[4 + 4 * i] = cset.f2.range2[i].nleft % 256; + blob->cursor = blob->size; + return blob; + } + } + return NULL; +} + +void close_charset(CFF_Charset cset) { + switch (cset.t) { + case CFF_CHARSET_EXPERT: + case CFF_CHARSET_EXPERTSUBSET: + case CFF_CHARSET_ISOADOBE: + break; + case CFF_CHARSET_FORMAT0: + if (cset.f0.glyph != NULL) free(cset.f0.glyph); + break; + case CFF_CHARSET_FORMAT1: + if (cset.f1.range1 != NULL) free(cset.f1.range1); + break; + case CFF_CHARSET_FORMAT2: + if (cset.f2.range2 != NULL) free(cset.f2.range2); + break; + } +} diff --git a/lib/libcff/cff-charset.h b/lib/libcff/cff-charset.h new file mode 100644 index 00000000..fc5f2ee9 --- /dev/null +++ b/lib/libcff/cff-charset.h @@ -0,0 +1,62 @@ +#ifndef CARYLL_CFF_CHARSET_H +#define CARYLL_CFF_CHARSET_H + +#include +#include +#include +#include +#include +#include "cff-util.h" +#include "cff-value.h" + +enum { + CFF_CHARSET_ISOADOBE = 0, + CFF_CHARSET_UNSPECED = 0, + CFF_CHARSET_EXPERT = 1, + CFF_CHARSET_EXPERTSUBSET = 2, + CFF_CHARSET_FORMAT0 = 3, + CFF_CHARSET_FORMAT1 = 4, + CFF_CHARSET_FORMAT2 = 5, +}; + +// CFF Charset Structures +typedef struct { + uint8_t format; + uint16_t *glyph; +} charset_f0; + +typedef struct { + uint16_t first; + uint8_t nleft; +} charset_range1; + +typedef struct { + uint8_t format; + charset_range1 *range1; +} charset_f1; + +typedef struct { + uint16_t first; + uint16_t nleft; +} charset_range2; + +typedef struct { + uint8_t format; + charset_range2 *range2; +} charset_f2; + +typedef struct { + uint32_t t; + uint32_t s; // size + union { + charset_f0 f0; + charset_f1 f1; + charset_f2 f2; + }; +} CFF_Charset; + +void close_charset(CFF_Charset cset); +void parse_charset(uint8_t *data, int32_t offset, uint16_t nchars, CFF_Charset *charsets); +caryll_buffer *compile_charset(CFF_Charset cset); + +#endif diff --git a/lib/libcff/cff-dict.c b/lib/libcff/cff-dict.c new file mode 100644 index 00000000..132632b6 --- /dev/null +++ b/lib/libcff/cff-dict.c @@ -0,0 +1,126 @@ +#include "libcff.h" + +// DICT util functions +void cff_delete_dict(CFF_Dict *dict) { + if (!dict) return; + for (uint32_t j = 0; j < dict->count; j++) { free(dict->ents[j].vals); } + free(dict->ents); + free(dict); +} + +void esrap_dict(CFF_Dict *d) { + uint32_t i; + + if (d != NULL) { + for (i = 0; i < d->count; i++) { + if (d->ents[i].vals != NULL) free(d->ents[i].vals); + } + + free(d->ents); + free(d); + } +} + +CFF_Dict *parse_dict(uint8_t *data, uint32_t len) { + CFF_Dict *dict = calloc(1, sizeof(CFF_Dict)); + uint32_t index = 0, advance; + CFF_Value val, stack[48]; + uint8_t *temp = data; + + while (temp < data + len) { + advance = decode_cff_token(temp, &val); + + switch (val.t) { + case CFF_OPERATOR: + dict->ents = realloc(dict->ents, sizeof(CFF_Dict_Entry) * (dict->count + 1)); + dict->ents[dict->count].op = val.i; + dict->ents[dict->count].cnt = index; + dict->ents[dict->count].vals = calloc(index, sizeof(CFF_Value)); + memcpy(dict->ents[dict->count].vals, stack, sizeof(CFF_Value) * index); + dict->count++; + index = 0; + break; + case CFF_INTEGER: + case CFF_DOUBLE: + stack[index++] = val; + break; + } + + temp += advance; + } + + return dict; +} + +void parse_dict_callback(uint8_t *data, uint32_t len, void *context, + void (*callback)(uint32_t op, uint8_t top, CFF_Value *stack, + void *context)) { + uint8_t index = 0; + uint32_t advance; + CFF_Value val, stack[256]; + uint8_t *temp = data; + + while (temp < data + len) { + advance = decode_cff_token(temp, &val); + + switch (val.t) { + case CFF_OPERATOR: + callback(val.i, index, stack, context); + index = 0; + break; + + case CFF_INTEGER: + case CFF_DOUBLE: + stack[index++] = val; + break; + } + + temp += advance; + } +} + +typedef struct { + bool found; + CFF_Value res; + uint32_t op; + uint32_t idx; +} cff_get_key_context; + +static void callback_get_key(uint32_t op, uint8_t top, CFF_Value *stack, void *_context) { + cff_get_key_context *context = (cff_get_key_context *)_context; + if (op == context->op && context->idx <= top) { + context->found = true; + context->res = stack[context->idx]; + } +} + +CFF_Value parse_dict_key(uint8_t *data, uint32_t len, uint32_t op, uint32_t idx) { + cff_get_key_context context; + context.found = false; + context.idx = idx; + context.op = op; + context.res.t = 0; + context.res.i = -1; + + parse_dict_callback(data, len, &context, callback_get_key); + return context.res; +} + +caryll_buffer *compile_dict(CFF_Dict *dict) { + caryll_buffer *blob = bufnew(); + for (uint32_t i = 0; i < dict->count; i++) { + for (uint32_t j = 0; j < dict->ents[i].cnt; j++) { + caryll_buffer *blob_val; + if (dict->ents[i].vals[j].t == CFF_INTEGER) { + blob_val = encode_cff_number(dict->ents[i].vals[j].i); + } else if (dict->ents[i].vals[j].t == CFF_DOUBLE) { + blob_val = encode_cff_real(dict->ents[i].vals[j].d); + } else { + blob_val = encode_cff_number(0); + } + bufwrite_bufdel(blob, blob_val); + } + bufwrite_bufdel(blob, encode_cff_operator(dict->ents[i].op)); + } + return blob; +} diff --git a/lib/libcff/cff-dict.h b/lib/libcff/cff-dict.h new file mode 100644 index 00000000..810a6013 --- /dev/null +++ b/lib/libcff/cff-dict.h @@ -0,0 +1,33 @@ +#ifndef CARYLL_CFF_DICT_H +#define CARYLL_CFF_DICT_H + +#include +#include +#include +#include +#include +#include "cff-value.h" + +typedef struct { + uint32_t op; + uint32_t cnt; + CFF_Value *vals; +} CFF_Dict_Entry; + +typedef struct { + uint32_t count; + CFF_Dict_Entry *ents; +} CFF_Dict; + +void cff_delete_dict(CFF_Dict *dict); +void esrap_dict(CFF_Dict *d); +CFF_Dict *parse_dict(uint8_t *data, uint32_t len); + +void parse_dict_callback(uint8_t *data, uint32_t len, void *context, + void (*callback)(uint32_t op, uint8_t top, CFF_Value *stack, + void *context)); +CFF_Value parse_dict_key(uint8_t *data, uint32_t len, uint32_t op, uint32_t idx); + +caryll_buffer *compile_dict(CFF_Dict *dict); + +#endif diff --git a/lib/libcff/cff-fdselect.c b/lib/libcff/cff-fdselect.c new file mode 100644 index 00000000..583726ee --- /dev/null +++ b/lib/libcff/cff-fdselect.c @@ -0,0 +1,78 @@ +#include "cff-fdselect.h" + +void close_fdselect(CFF_FDSelect fds) { + switch (fds.t) { + case CFF_FDSELECT_FORMAT0: + if (fds.f0.fds != NULL) free(fds.f0.fds); + break; + case CFF_FDSELECT_FORMAT3: + if (fds.f3.range3 != NULL) free(fds.f3.range3); + break; + case CFF_FDSELECT_UNSPECED: + break; + } +} + +caryll_buffer *compile_fdselect(CFF_FDSelect fd) { + switch (fd.t) { + case CFF_FDSELECT_UNSPECED: { + return bufnew(); + } + case CFF_FDSELECT_FORMAT0: { + caryll_buffer *blob = bufnew(); + blob->size = 1 + fd.s; + blob->data = calloc(blob->size, sizeof(uint8_t)); + for (uint16_t j = 0; j < fd.s; j++) { blob->data[j] = fd.f0.fds[j]; } + return blob; + } + case CFF_FDSELECT_FORMAT3: { + caryll_buffer *blob = bufnew(); + blob->size = 5 + fd.f3.nranges * 3; + blob->data = calloc(blob->size, sizeof(uint8_t)); + blob->data[0] = 3; + blob->data[1] = fd.f3.nranges / 256; + blob->data[2] = fd.f3.nranges % 256; + for (int i = 0; i < fd.f3.nranges; i++) + blob->data[3 + 3 * i] = fd.f3.range3[i].first / 256, + blob->data[4 + 3 * i] = fd.f3.range3[i].first % 256, + blob->data[5 + 3 * i] = fd.f3.range3[i].fd; + blob->data[blob->size - 2] = fd.f3.sentinel / 256; + blob->data[blob->size - 1] = fd.f3.sentinel % 256; + return blob; + } + default: { return NULL; } + } +} + +void parse_fdselect(uint8_t *data, int32_t offset, uint16_t nchars, CFF_FDSelect *fdselect) { + fdselect->t = data[offset]; + + switch (data[offset]) { + case 0: + fdselect->t = CFF_FDSELECT_FORMAT0; + { + fdselect->f0.format = 0; + fdselect->s = nchars - 1; + fdselect->f0.fds = calloc(nchars - 1, sizeof(uint8_t)); + + for (uint32_t i = 0; i < nchars - 1; i++) + fdselect->f0.fds[i] = gu1(data, offset + 1 + i); + } + break; + case 3: + fdselect->t = CFF_FDSELECT_FORMAT3; + { + fdselect->f3.format = 3; + fdselect->f3.nranges = gu2(data, offset + 1); + fdselect->f3.range3 = calloc(fdselect->f3.nranges, sizeof(fdselect_range3)); + + for (uint32_t i = 0; i < fdselect->f3.nranges; i++) { + fdselect->f3.range3[i].first = gu2(data, offset + 3 + i * 3); + fdselect->f3.range3[i].fd = gu1(data, offset + 5 + i * 3); + } + + fdselect->f3.sentinel = gu2(data, offset + (fdselect->f3.nranges + 1) * 3); + } + break; + } +} diff --git a/lib/libcff/cff-fdselect.h b/lib/libcff/cff-fdselect.h new file mode 100644 index 00000000..4ba2a43e --- /dev/null +++ b/lib/libcff/cff-fdselect.h @@ -0,0 +1,48 @@ +#ifndef CARYLL_CFF_FDSELECT_H +#define CARYLL_CFF_FDSELECT_H + +#include +#include +#include +#include +#include +#include "cff-util.h" +#include "cff-value.h" + +enum { + CFF_FDSELECT_FORMAT0, + CFF_FDSELECT_FORMAT3, + CFF_FDSELECT_UNSPECED, +}; + +typedef struct { + uint8_t format; + uint8_t *fds; +} fdselect_f0; + +typedef struct { + uint16_t first; + uint8_t fd; +} fdselect_range3; + +typedef struct { + uint8_t format; + uint16_t nranges; + fdselect_range3 *range3; + uint16_t sentinel; +} fdselect_f3; + +typedef struct { + uint32_t t; + uint32_t s; + union { + fdselect_f0 f0; + fdselect_f3 f3; + }; +} CFF_FDSelect; + +void close_fdselect(CFF_FDSelect fds); +caryll_buffer *compile_fdselect(CFF_FDSelect fd); +void parse_fdselect(uint8_t *data, int32_t offset, uint16_t nchars, CFF_FDSelect *fdselect); + +#endif diff --git a/lib/libcff/cff-index.c b/lib/libcff/cff-index.c new file mode 100644 index 00000000..d732c1d1 --- /dev/null +++ b/lib/libcff/cff-index.c @@ -0,0 +1,150 @@ +#include "cff-index.h" +// INDEX util functions +CFF_Index *cff_index_init(void) { + CFF_Index *out = calloc(1, sizeof(CFF_Index)); + return out; +} + +void esrap_index(CFF_Index in) { + if (in.offset != NULL) free(in.offset); + if (in.data != NULL) free(in.data); +} + +void empty_index(CFF_Index *in) { + in->count = 0; + in->offSize = 0; + in->offset = NULL; + in->data = NULL; +} + +void cff_index_fini(CFF_Index *out) { + if (out != NULL) { + if (out->offset != NULL) free(out->offset); + if (out->data != NULL) free(out->data); + free(out); + } +} + +uint32_t count_index(CFF_Index i) { + if (i.count != 0) + return 3 + (i.offset[i.count] - 1) + ((i.count + 1) * i.offSize); + else + return 3; +} + +void parse_index(uint8_t *data, uint32_t pos, CFF_Index *in) { + in->count = gu2(data, pos); + in->offSize = gu1(data, pos + 2); + + if (in->count > 0) { + in->offset = calloc(in->count + 1, sizeof(uint32_t)); + + for (int i = 0; i <= in->count; i++) { + switch (in->offSize) { + case 1: + in->offset[i] = gu1(data, pos + 3 + (i * in->offSize)); + break; + case 2: + in->offset[i] = gu2(data, pos + 3 + (i * in->offSize)); + break; + case 3: + in->offset[i] = gu3(data, pos + 3 + (i * in->offSize)); + break; + case 4: + in->offset[i] = gu4(data, pos + 3 + (i * in->offSize)); + break; + } + } + + in->data = calloc(in->offset[in->count] - 1, sizeof(uint8_t)); + memcpy(in->data, data + pos + 3 + (in->count + 1) * in->offSize, in->offset[in->count] - 1); + } else { + in->offset = NULL; + in->data = NULL; + } +} + +CFF_Index *cff_buildindex_callback(void *context, uint32_t length, + caryll_buffer *(*fn)(void *, uint32_t)) { + CFF_Index *idx = cff_index_init(); + idx->count = length; + NEW_N(idx->offset, idx->count + 1); + idx->offset[0] = 1; + idx->data = NULL; + + size_t used = 0; + size_t blank = 0; + for (uint32_t i = 0; i < length; i++) { + caryll_buffer *blob = fn(context, i); + if (blank < blob->size) { + used += blob->size; + blank = (used >> 1) & 0xFFFFFF; + idx->data = realloc(idx->data, sizeof(uint8_t) * (used + blank)); + } else { + used += blob->size; + blank -= blob->size; + } + idx->offset[i + 1] = (uint32_t)(blob->size + idx->offset[i]); + memcpy(idx->data + idx->offset[i] - 1, blob->data, blob->size); + buffree(blob); + } + idx->offSize = 4; + return idx; +} + +caryll_buffer *compile_index(CFF_Index index) { + caryll_buffer *blob = bufnew(); + uint32_t i; + + uint32_t lastOffset = index.offset[index.count]; + if (lastOffset < 0x100) { + index.offSize = 1; + } else if (lastOffset < 0x10000) { + index.offSize = 2; + } else if (lastOffset < 0x1000000) { + index.offSize = 3; + } else { + index.offSize = 4; + } + + if (index.count != 0) + blob->size = 3 + (index.offset[index.count] - 1) + ((index.count + 1) * index.offSize); + else + blob->size = 3; + + blob->data = calloc(blob->size, sizeof(uint8_t)); + blob->data[0] = index.count / 256; + blob->data[1] = index.count % 256; + blob->data[2] = index.offSize; + + if (index.count > 0) { + for (i = 0; i <= index.count; i++) { + switch (index.offSize) { + case 1: + blob->data[3 + i] = index.offset[i]; + break; + case 2: + blob->data[3 + i * 2] = index.offset[i] / 256; + blob->data[4 + i * 2] = index.offset[i] % 256; + break; + case 3: + blob->data[3 + i * 3] = index.offset[i] / 65536; + blob->data[4 + i * 3] = (index.offset[i] % 65536) / 256; + blob->data[5 + i * 3] = (index.offset[i] % 65536) % 256; + break; + case 4: + blob->data[3 + i * 4] = (index.offset[i] / 65536) / 256; + blob->data[4 + i * 4] = (index.offset[i] / 65536) % 256; + blob->data[5 + i * 4] = (index.offset[i] % 65536) / 256; + blob->data[6 + i * 4] = (index.offset[i] % 65536) % 256; + break; + } + } + + if (index.data != NULL) + memcpy(blob->data + 3 + ((index.count + 1) * index.offSize), index.data, + index.offset[index.count] - 1); + } + blob->cursor = blob->size; + return blob; +} diff --git a/lib/libcff/cff-index.h b/lib/libcff/cff-index.h new file mode 100644 index 00000000..3e244dad --- /dev/null +++ b/lib/libcff/cff-index.h @@ -0,0 +1,33 @@ +#ifndef CARYLL_CFF_INDEX_H +#define CARYLL_CFF_INDEX_H + +#include +#include +#include +#include +#include + +#include "cff-util.h" +#include "cff-value.h" + +typedef struct { + uint16_t count; + uint8_t offSize; + uint32_t *offset; + uint8_t *data; +} CFF_Index; + +extern CFF_Index *cff_index_init(void); +extern void cff_index_fini(CFF_Index *out); +extern void esrap_index(CFF_Index in); +extern void empty_index(CFF_Index *in); +uint32_t count_index(CFF_Index i); + +void parse_index(uint8_t *data, uint32_t pos, CFF_Index *in); + +CFF_Index *cff_buildindex_callback(void *context, uint32_t length, + caryll_buffer *(*fn)(void *, uint32_t)); + +caryll_buffer *compile_index(CFF_Index index); + +#endif diff --git a/lib/libcff/cff-parser.c b/lib/libcff/cff-parser.c index 435b46fa..20dcb4b5 100644 --- a/lib/libcff/cff-parser.c +++ b/lib/libcff/cff-parser.c @@ -13,187 +13,6 @@ #include "libcff.h" -static inline uint32_t gu1(uint8_t *s, uint32_t p) { - uint32_t b0 = *(s + p); - return b0; -} - -static inline uint32_t gu2(uint8_t *s, uint32_t p) { - uint32_t b0 = *(s + p) << 8; - uint32_t b1 = *(s + p + 1); - return b0 | b1; -} - -static inline uint32_t gu3(uint8_t *s, uint32_t p) { - uint32_t b0 = *(s + p) << 16; - uint32_t b1 = *(s + p + 1) << 8; - uint32_t b2 = *(s + p + 2); - return b0 | b1 | b2; -} -static inline uint32_t gu4(uint8_t *s, uint32_t p) { - uint32_t b0 = *(s + p) << 24; - uint32_t b1 = *(s + p + 1) << 16; - uint32_t b2 = *(s + p + 2) << 8; - uint32_t b3 = *(s + p + 3); - return b0 | b1 | b2 | b3; -} - -static uint32_t count_index(CFF_INDEX i) { - if (i.count != 0) - return 3 + (i.offset[i.count] - 1) + ((i.count + 1) * i.offSize); - else - return 3; -} - -void esrap_index(CFF_INDEX in) { - if (in.offset != NULL) free(in.offset); - if (in.data != NULL) free(in.data); -} - -void empty_index(CFF_INDEX *in) { - in->count = 0; - in->offSize = 0; - in->offset = NULL; - in->data = NULL; -} - -static void parse_index(uint8_t *data, uint32_t pos, CFF_INDEX *in) { - in->count = gu2(data, pos); - in->offSize = gu1(data, pos + 2); - - if (in->count > 0) { - in->offset = calloc(in->count + 1, sizeof(uint32_t)); - - for (int i = 0; i <= in->count; i++) { - switch (in->offSize) { - case 1: - in->offset[i] = gu1(data, pos + 3 + (i * in->offSize)); - break; - case 2: - in->offset[i] = gu2(data, pos + 3 + (i * in->offSize)); - break; - case 3: - in->offset[i] = gu3(data, pos + 3 + (i * in->offSize)); - break; - case 4: - in->offset[i] = gu4(data, pos + 3 + (i * in->offSize)); - break; - } - } - - in->data = calloc(in->offset[in->count] - 1, sizeof(uint8_t)); - memcpy(in->data, data + pos + 3 + (in->count + 1) * in->offSize, in->offset[in->count] - 1); - } else { - in->offset = NULL; - in->data = NULL; - } -} - -double cffnum(CFF_Value val) { - if (val.t == CFF_INTEGER) return val.i; - if (val.t == CFF_DOUBLE) return val.d; - return 0; -} - -void esrap_dict(CFF_Dict *d) { - uint32_t i; - - if (d != NULL) { - for (i = 0; i < d->count; i++) { - if (d->ents[i].vals != NULL) free(d->ents[i].vals); - } - - free(d->ents); - free(d); - } -} - -CFF_Dict *parse_dict(uint8_t *data, uint32_t len) { - CFF_Dict *dict = calloc(1, sizeof(CFF_Dict)); - uint32_t index = 0, advance; - CFF_Value val, stack[48]; - uint8_t *temp = data; - - while (temp < data + len) { - advance = decode_cff_token(temp, &val); - - switch (val.t) { - case CFF_OPERATOR: - dict->ents = realloc(dict->ents, sizeof(CFF_Dict_Entry) * (dict->count + 1)); - dict->ents[dict->count].op = val.i; - dict->ents[dict->count].cnt = index; - dict->ents[dict->count].vals = calloc(index, sizeof(CFF_Value)); - memcpy(dict->ents[dict->count].vals, stack, sizeof(CFF_Value) * index); - dict->count++; - index = 0; - break; - case CFF_INTEGER: - case CFF_DOUBLE: - stack[index++] = val; - break; - } - - temp += advance; - } - - return dict; -} - -void cff_dict_callback(uint8_t *data, uint32_t len, void *context, - void (*callback)(uint32_t op, uint8_t top, CFF_Value *stack, - void *context)) { - uint8_t index = 0; - uint32_t advance; - CFF_Value val, stack[256]; - uint8_t *temp = data; - - while (temp < data + len) { - advance = decode_cff_token(temp, &val); - - switch (val.t) { - case CFF_OPERATOR: - callback(val.i, index, stack, context); - index = 0; - break; - - case CFF_INTEGER: - case CFF_DOUBLE: - stack[index++] = val; - break; - } - - temp += advance; - } -} - -typedef struct { - bool found; - CFF_Value res; - uint32_t op; - uint32_t idx; -} cff_get_key_context; - -static void callback_get_key(uint32_t op, uint8_t top, CFF_Value *stack, void *_context) { - cff_get_key_context *context = (cff_get_key_context *)_context; - if (op == context->op && context->idx <= top) { - context->found = true; - context->res = stack[context->idx]; - } -} - -CFF_Value parse_dict_key(uint8_t *data, uint32_t len, uint32_t op, uint32_t idx) { - cff_get_key_context context; - context.found = false; - context.idx = idx; - context.op = op; - context.res.t = 0; - context.res.i = -1; - - cff_dict_callback(data, len, &context, callback_get_key); - - return context.res; -} - static void parse_encoding(CFF_File *cff, int32_t offset, CFF_Encoding *enc) { uint8_t *data = cff->raw_data; @@ -241,102 +60,6 @@ static void parse_encoding(CFF_File *cff, int32_t offset, CFF_Encoding *enc) { } } -static void parse_charset(CFF_File *cff, int32_t offset, CFF_Charset *charsets) { - uint32_t i; - if (offset == CFF_CHARSET_ISOADOBE) - charsets->t = CFF_CHARSET_ISOADOBE; - else if (offset == CFF_CHARSET_EXPERT) - charsets->t = CFF_CHARSET_EXPERT; - else if (offset == CFF_CHARSET_EXPERTSUBSET) - charsets->t = CFF_CHARSET_EXPERTSUBSET; - else { - // NOTE: gid 1 will always be named as .notdef - switch (cff->raw_data[offset]) { - case 0: - charsets->t = CFF_CHARSET_FORMAT0; - { - charsets->s = cff->char_strings.count - 1; - charsets->f0.glyph = calloc(cff->char_strings.count - 1, sizeof(uint16_t)); - - for (i = 0; i < charsets->s; i++) - charsets->f0.glyph[i] = gu2(cff->raw_data, offset + 1 + i * 2); - } - break; - case 1: - charsets->t = CFF_CHARSET_FORMAT1; - { - uint32_t size; - uint32_t glyphsEncodedSofar = 1; - for (i = 0; glyphsEncodedSofar < cff->char_strings.count; i++) { - glyphsEncodedSofar += 1 + gu1(cff->raw_data, offset + 3 + i * 3); - } - - size = i; - charsets->s = size; - charsets->f1.range1 = calloc(i + 1, sizeof(charset_range1)); - for (i = 0; i < size; i++) { - charsets->f1.range1[i].first = gu2(cff->raw_data, offset + 1 + i * 3); - charsets->f1.range1[i].nleft = gu1(cff->raw_data, offset + 3 + i * 3); - } - } - break; - case 2: - charsets->t = CFF_CHARSET_FORMAT2; - { - uint32_t size; - uint32_t glyphsEncodedSofar = 1; - for (i = 0; glyphsEncodedSofar < cff->char_strings.count; i++) { - glyphsEncodedSofar += 1 + gu2(cff->raw_data, offset + 3 + i * 4); - } - - size = i; - charsets->s = size; - charsets->f2.range2 = calloc(i + 1, sizeof(charset_range2)); - - for (i = 0; i < size; i++) { - charsets->f2.range2[i].first = gu2(cff->raw_data, offset + 1 + i * 4); - charsets->f2.range2[i].nleft = gu2(cff->raw_data, offset + 3 + i * 4); - } - } - break; - } - } -} - -static void parse_fdselect(CFF_File *cff, int32_t offset, CFF_FDSelect *fdselect) { - uint8_t *data = cff->raw_data; - fdselect->t = data[offset]; - - switch (data[offset]) { - case 0: - fdselect->t = CFF_FDSELECT_FORMAT0; - { - fdselect->f0.format = 0; - fdselect->s = cff->char_strings.count - 1; - fdselect->f0.fds = calloc(cff->char_strings.count - 1, sizeof(uint8_t)); - - for (uint32_t i = 0; i < cff->char_strings.count - 1; i++) - fdselect->f0.fds[i] = gu1(data, offset + 1 + i); - } - break; - case 3: - fdselect->t = CFF_FDSELECT_FORMAT3; - { - fdselect->f3.format = 3; - fdselect->f3.nranges = gu2(data, offset + 1); - fdselect->f3.range3 = calloc(fdselect->f3.nranges, sizeof(fdselect_range3)); - - for (uint32_t i = 0; i < fdselect->f3.nranges; i++) { - fdselect->f3.range3[i].first = gu2(data, offset + 3 + i * 3); - fdselect->f3.range3[i].fd = gu1(data, offset + 5 + i * 3); - } - - fdselect->f3.sentinel = gu2(data, offset + (fdselect->f3.nranges + 1) * 3); - } - break; - } -} - static void parse_cff_bytecode(CFF_File *cff) { uint32_t pos; int32_t offset; @@ -406,7 +129,7 @@ static void parse_cff_bytecode(CFF_File *cff) { .i; if (offset != -1) { - parse_charset(cff, offset, &cff->charsets); + parse_charset(cff->raw_data, offset, cff->char_strings.count, &cff->charsets); } else { cff->charsets.t = CFF_CHARSET_UNSPECED; } @@ -417,7 +140,7 @@ static void parse_cff_bytecode(CFF_File *cff) { .i; if (offset != -1) { - parse_fdselect(cff, offset, &cff->fdselect); + parse_fdselect(cff->raw_data, offset, cff->char_strings.count, &cff->fdselect); } else { cff->fdselect.t = CFF_FDSELECT_UNSPECED; } @@ -474,46 +197,6 @@ CFF_File *CFF_stream_open(uint8_t *data, uint32_t len) { return file; } -CFF_File *CFF_file_open(const char *fname) { - CFF_File *file; - FILE *fptr = fopen(fname, "rb"); - - if (fptr != NULL) { - file = calloc(1, sizeof(CFF_File)); - fseek(fptr, 0, SEEK_END); - file->raw_length = ftell(fptr); - file->raw_data = calloc(file->raw_length, sizeof(uint8_t)); - file->cnt_glyph = 0; - fseek(fptr, 0, SEEK_SET); - (void)fread(file->raw_data, sizeof(uint8_t), file->raw_length, fptr); - parse_cff_bytecode(file); - fclose(fptr); - } else - file = NULL; - - return file; -} - -CFF_File *CFF_sfnt_open(const char *fname, uint32_t offset, uint32_t len) { - CFF_File *file; - FILE *fptr = fopen(fname, "rb"); - - if (fptr != NULL) { - file = calloc(1, sizeof(CFF_File)); - file->raw_data = calloc(len, sizeof(uint8_t)); - file->raw_length = len; - file->cnt_glyph = 0; - fseek(fptr, offset, SEEK_SET); - (void)fread(file->raw_data, sizeof(uint8_t), len, fptr); - parse_cff_bytecode(file); - fclose(fptr); - } else { - file = NULL; - } - - return file; -} - void CFF_close(CFF_File *file) { if (file != NULL) { if (file->raw_data != NULL) free(file->raw_data); @@ -542,39 +225,15 @@ void CFF_close(CFF_File *file) { break; } - switch (file->charsets.t) { - case CFF_CHARSET_EXPERT: - case CFF_CHARSET_EXPERTSUBSET: - case CFF_CHARSET_ISOADOBE: - break; - case CFF_CHARSET_FORMAT0: - if (file->charsets.f0.glyph != NULL) free(file->charsets.f0.glyph); - break; - case CFF_CHARSET_FORMAT1: - if (file->charsets.f1.range1 != NULL) free(file->charsets.f1.range1); - break; - case CFF_CHARSET_FORMAT2: - if (file->charsets.f2.range2 != NULL) free(file->charsets.f2.range2); - break; - } - - switch (file->fdselect.t) { - case CFF_FDSELECT_FORMAT0: - if (file->fdselect.f0.fds != NULL) free(file->fdselect.f0.fds); - break; - case CFF_FDSELECT_FORMAT3: - if (file->fdselect.f3.range3 != NULL) free(file->fdselect.f3.range3); - break; - case CFF_FDSELECT_UNSPECED: - break; - } + close_charset(file->charsets); + close_fdselect(file->fdselect); free(file); } } -uint8_t parse_subr(uint16_t idx, uint8_t *raw, CFF_INDEX fdarray, CFF_FDSelect select, - CFF_INDEX *subr) { +uint8_t parse_subr(uint16_t idx, uint8_t *raw, CFF_Index fdarray, CFF_FDSelect select, + CFF_Index *subr) { uint8_t fd = 0; int32_t off_private, len_private; int32_t off_subr; @@ -656,7 +315,7 @@ static double callback_nopgetrand(void *context) { return 0; } break; \ } \ } -void parse_outline_callback(uint8_t *data, uint32_t len, CFF_INDEX gsubr, CFF_INDEX lsubr, +void parse_outline_callback(uint8_t *data, uint32_t len, CFF_Index gsubr, CFF_Index lsubr, CFF_Stack *stack, void *outline, cff_outline_builder_interface methods) { uint16_t gsubr_bias = compute_subr_bias(gsubr.count); diff --git a/lib/libcff/cff-string.c b/lib/libcff/cff-string.c index cc1a580e..df611e0d 100644 --- a/lib/libcff/cff-string.c +++ b/lib/libcff/cff-string.c @@ -400,19 +400,7 @@ static const char *const string_standard[391] = { }; // substring in name/string INDEX -static void print_segment(uint8_t *data, uint32_t pos, uint32_t len) { - char *str = calloc(len + 1, sizeof(uint8_t)); - strncpy(str, (const char *)data + pos, len); - printf("%s", str); - free(str); -} - -void print_index(CFF_INDEX idx) { - for (int i = 0; i < idx.count; i++) - print_segment(idx.data, idx.offset[i] - 1, idx.offset[i + 1] - idx.offset[i]), printf("\n"); -} - -char *get_cff_sid(uint16_t idx, CFF_INDEX str) { +char *get_cff_sid(uint16_t idx, CFF_Index str) { if (idx >= 0 && idx <= 390) return strdup(string_standard[idx]); if (str.count > 0 && idx - 391 < str.count) { char *dup = calloc(str.offset[idx - 390] - str.offset[idx - 391] + 1, sizeof(uint8_t)); @@ -423,7 +411,7 @@ char *get_cff_sid(uint16_t idx, CFF_INDEX str) { return strdup("Unknown"); } -sds sdsget_cff_sid(uint16_t idx, CFF_INDEX str) { +sds sdsget_cff_sid(uint16_t idx, CFF_Index str) { if (idx >= 0 && idx <= 390) { return sdsnew(string_standard[idx]); } else if (str.count > 0 && idx - 391 < str.count) { diff --git a/lib/libcff/cff-types.c b/lib/libcff/cff-types.c deleted file mode 100644 index 93c4e065..00000000 --- a/lib/libcff/cff-types.c +++ /dev/null @@ -1,35 +0,0 @@ -#include "libcff.h" - -// INDEX util functions -CFF_INDEX *cff_index_init(void) { - CFF_INDEX *out = calloc(1, sizeof(CFF_INDEX)); - return out; -} - -void cff_index_fini(CFF_INDEX *out) { - if (out != NULL) { - if (out->offset != NULL) free(out->offset); - if (out->data != NULL) free(out->data); - free(out); - } -} - -// DICT util functions -static void printf_cff_val(CFF_Value val) { - if (val.t == CFF_INTEGER) fprintf(stderr, "%d", val.i); - if (val.t == CFF_DOUBLE) fprintf(stderr, "%f", val.d); -} -static void callback_print_dict(uint32_t op, uint8_t top, CFF_Value *stack, void *context) { - for (uint32_t i = 0; i < top; i++) printf_cff_val(stack[i]), fprintf(stderr, " "); - fprintf(stderr, "%s\n", op_cff_name(op)); -} -void print_dict(uint8_t *data, uint32_t len) { - return cff_dict_callback(data, len, NULL, callback_print_dict); -} - -void cff_delete_dict(CFF_Dict *dict) { - if (!dict) return; - for (uint32_t j = 0; j < dict->count; j++) { free(dict->ents[j].vals); } - free(dict->ents); - free(dict); -} diff --git a/lib/libcff/cff-util.h b/lib/libcff/cff-util.h new file mode 100644 index 00000000..5a0965f9 --- /dev/null +++ b/lib/libcff/cff-util.h @@ -0,0 +1,123 @@ +#ifndef CARYLL_CFF_UTIL_H +#define CARYLL_CFF_UTIL_H + +#include +#include +#include +#include +#include + +// clang-format off +// CFF DICT Operators +enum { + op_version = 0x00, op_Copyright = 0x0c00, + op_Notice = 0x01, op_isFixedPitch = 0x0c01, + op_FullName = 0x02, op_ItalicAngle = 0x0c02, + op_FamilyName = 0x03, op_UnderlinePosition = 0x0c03, + op_Weight = 0x04, op_UnderlineThickness = 0x0c04, + op_FontBBox = 0x05, op_PaintType = 0x0c05, + op_BlueValues = 0x06, op_CharstringType = 0x0c06, + op_OtherBlues = 0x07, op_FontMatrix = 0x0c07, + op_FamilyBlues = 0x08, op_StrokeWidth = 0x0c08, + op_FamilyOtherBlues = 0x09, op_BlueScale = 0x0c09, + op_StdHW = 0x0a, op_BlueShift = 0x0c0a, + op_StdVW = 0x0b, op_BlueFuzz = 0x0c0b, + /* 0x0c escape */ op_StemSnapH = 0x0c0c, + op_UniqueID = 0x0d, op_StemSnapV = 0x0c0d, + op_XUID = 0x0e, op_ForceBold = 0x0c0e, + op_charset = 0x0f, /* 0x0c0f Reserved */ + op_Encoding = 0x10, /* 0x0c10 Reserved */ + op_CharStrings = 0x11, op_LanguageGroup = 0x0c11, + op_Private = 0x12, op_ExpansionFactor = 0x0c12, + op_Subrs = 0x13, op_initialRandomSeed = 0x0c13, + op_defaultWidthX = 0x14, op_SyntheicBase = 0x0c14, + op_nominalWidthX = 0x15, op_PostScript = 0x0c15, + op_BaseFontName = 0x0c16, + op_BaseFontBlend = 0x0c17, + /* 0x0c18 Reserved */ + /* 0x0c19 Reserved */ + /* 0x0c1a Reserved */ + /* 0x0c1b Reserved */ + /* 0x0c1c Reserved */ + /* 0x0c1d Reserved */ + op_ROS = 0x0c1e, + op_CIDFontVersion = 0x0c1f, + op_CIDFontRevision = 0x0c20, + op_CIDFontType = 0x0c21, + op_CIDCount = 0x0c22, + op_UIDBase = 0x0c23, + op_FDArray = 0x0c24, + op_FDSelect = 0x0c25, + op_FontName = 0x0c26, +}; + +// Type2 CharString Operators +enum { + /* 0x00 Reserved */ /* 0x0c00 Reserved */ + op_hstem = 0x01, /* 0x0c01 Reserved */ + /* 0x02 Reserved */ /* 0x0c02 Reserved */ + op_vstem = 0x03, op_and = 0x0c03, + op_vmoveto = 0x04, op_or = 0x0c04, + op_rlineto = 0x05, op_not = 0x0c05, + op_hlineto = 0x06, /* 0x0c06 Reserved */ + op_vlineto = 0x07, /* 0x0c07 Reserved */ + op_rrcurveto = 0x08, /* 0x0c08 Reserved */ + /* 0x09 Reserved */ op_abs = 0x0c09, + op_callsubr = 0x0a, op_add = 0x0c0a, + op_return = 0x0b, op_sub = 0x0c0b, + /* 0x0c escape */ op_div = 0x0c0c, + /* 0x0d Reserved */ /* 0x0c0d Reserved */ + op_endchar = 0x0e, op_neg = 0x0c0e, + /* 0x0f Reserved */ op_eq = 0x0c0f, + /* 0x10 Reserved */ /* 0x0c10 Reserved */ + /* 0x11 Reserved */ /* 0x0c11 Reserved */ + op_hstemhm = 0x12, op_drop = 0x0c12, + op_hintmask = 0x13, /* 0x0c13 Reserved */ + op_cntrmask = 0x14, op_put = 0x0c14, + op_rmoveto = 0x15, op_get = 0x0c15, + op_hmoveto = 0x16, op_ifelse = 0x0c16, + op_vstemhm = 0x17, op_random = 0x0c17, + op_rcurveline = 0x18, op_mul = 0x0c18, + op_rlinecurve = 0x19, /* 0x0c19 Reserved */ + op_vvcurveto = 0x1a, op_sqrt = 0x0c1a, + op_hhcurveto = 0x1b, op_dup = 0x0c1b, + /* 0x1c short int */ op_exch = 0x0c1c, + op_callgsubr = 0x1d, op_index = 0x0c1d, + op_vhcurveto = 0x1e, op_roll = 0x0c1e, + op_hvcurveto = 0x1f, /* 0x0c1f Reserved */ + /* 0x0c20 Reserved */ + /* 0x0c21 Reserved */ + op_hflex = 0x0c22, + op_flex = 0x0c23, + op_hflex1 = 0x0c24, + op_flex1 = 0x0c25, +}; +// clang-format on + +// parser util functions +static INLINE uint32_t gu1(uint8_t *s, uint32_t p) { + uint32_t b0 = *(s + p); + return b0; +} + +static INLINE uint32_t gu2(uint8_t *s, uint32_t p) { + uint32_t b0 = *(s + p) << 8; + uint32_t b1 = *(s + p + 1); + return b0 | b1; +} + +static INLINE uint32_t gu3(uint8_t *s, uint32_t p) { + uint32_t b0 = *(s + p) << 16; + uint32_t b1 = *(s + p + 1) << 8; + uint32_t b2 = *(s + p + 2); + return b0 | b1 | b2; +} +static INLINE uint32_t gu4(uint8_t *s, uint32_t p) { + uint32_t b0 = *(s + p) << 24; + uint32_t b1 = *(s + p + 1) << 16; + uint32_t b2 = *(s + p + 2) << 8; + uint32_t b3 = *(s + p + 3); + return b0 | b1 | b2 | b3; +} + +#endif diff --git a/lib/libcff/cff-value.c b/lib/libcff/cff-value.c new file mode 100644 index 00000000..ba4d1a00 --- /dev/null +++ b/lib/libcff/cff-value.c @@ -0,0 +1,7 @@ +#include "cff-value.h" + +double cffnum(CFF_Value val) { + if (val.t == CFF_INTEGER) return val.i; + if (val.t == CFF_DOUBLE) return val.d; + return 0; +} diff --git a/lib/libcff/cff-value.h b/lib/libcff/cff-value.h new file mode 100644 index 00000000..e86350d2 --- /dev/null +++ b/lib/libcff/cff-value.h @@ -0,0 +1,29 @@ +#ifndef CARYLL_CFF_VALUE_H +#define CARYLL_CFF_VALUE_H + +#include +#include +#include +#include +#include + +typedef enum { + CFF_OPERATOR = 1, + CS2_OPERATOR = 1, + CFF_INTEGER = 2, + CS2_OPERAND = 2, + CFF_DOUBLE = 3, + CS2_FRACTION = 3 +} CFF_Value_Type; + +typedef struct { + CFF_Value_Type t; + union { + int32_t i; + double d; + }; +} CFF_Value; + +double cffnum(CFF_Value v); + +#endif diff --git a/lib/libcff/cff-writer.c b/lib/libcff/cff-writer.c index 5b41311c..2cc4388b 100644 --- a/lib/libcff/cff-writer.c +++ b/lib/libcff/cff-writer.c @@ -14,187 +14,6 @@ caryll_buffer *compile_header(void) { return bufninit(4, 1, 0, 4, 4); } -caryll_buffer *compile_dict(CFF_Dict *dict) { - caryll_buffer *blob = bufnew(); - for (uint32_t i = 0; i < dict->count; i++) { - for (uint32_t j = 0; j < dict->ents[i].cnt; j++) { - caryll_buffer *blob_val; - if (dict->ents[i].vals[j].t == CFF_INTEGER) { - blob_val = encode_cff_number(dict->ents[i].vals[j].i); - } else if (dict->ents[i].vals[j].t == CFF_DOUBLE) { - blob_val = encode_cff_real(dict->ents[i].vals[j].d); - } else { - blob_val = encode_cff_number(0); - } - bufwrite_bufdel(blob, blob_val); - } - bufwrite_bufdel(blob, encode_cff_operator(dict->ents[i].op)); - } - return blob; -} - -CFF_INDEX *cff_buildindex_callback(void *context, uint32_t length, - caryll_buffer *(*fn)(void *, uint32_t)) { - CFF_INDEX *idx = cff_index_init(); - idx->count = length; - NEW_N(idx->offset, idx->count + 1); - idx->offset[0] = 1; - idx->data = NULL; - - size_t used = 0; - size_t blank = 0; - for (uint32_t i = 0; i < length; i++) { - caryll_buffer *blob = fn(context, i); - if (blank < blob->size) { - used += blob->size; - blank = (used >> 1) & 0xFFFFFF; - idx->data = realloc(idx->data, sizeof(uint8_t) * (used + blank)); - } else { - used += blob->size; - blank -= blob->size; - } - idx->offset[i + 1] = (uint32_t)(blob->size + idx->offset[i]); - memcpy(idx->data + idx->offset[i] - 1, blob->data, blob->size); - buffree(blob); - } - idx->offSize = 4; - return idx; -} - -caryll_buffer *compile_index(CFF_INDEX index) { - caryll_buffer *blob = bufnew(); - uint32_t i; - - uint32_t lastOffset = index.offset[index.count]; - if (lastOffset < 0x100) { - index.offSize = 1; - } else if (lastOffset < 0x10000) { - index.offSize = 2; - } else if (lastOffset < 0x1000000) { - index.offSize = 3; - } else { - index.offSize = 4; - } - - if (index.count != 0) - blob->size = 3 + (index.offset[index.count] - 1) + ((index.count + 1) * index.offSize); - else - blob->size = 3; - - blob->data = calloc(blob->size, sizeof(uint8_t)); - blob->data[0] = index.count / 256; - blob->data[1] = index.count % 256; - blob->data[2] = index.offSize; - - if (index.count > 0) { - for (i = 0; i <= index.count; i++) { - switch (index.offSize) { - case 1: - blob->data[3 + i] = index.offset[i]; - break; - case 2: - blob->data[3 + i * 2] = index.offset[i] / 256; - blob->data[4 + i * 2] = index.offset[i] % 256; - break; - case 3: - blob->data[3 + i * 3] = index.offset[i] / 65536; - blob->data[4 + i * 3] = (index.offset[i] % 65536) / 256; - blob->data[5 + i * 3] = (index.offset[i] % 65536) % 256; - break; - case 4: - blob->data[3 + i * 4] = (index.offset[i] / 65536) / 256; - blob->data[4 + i * 4] = (index.offset[i] / 65536) % 256; - blob->data[5 + i * 4] = (index.offset[i] % 65536) / 256; - blob->data[6 + i * 4] = (index.offset[i] % 65536) % 256; - break; - } - } - - if (index.data != NULL) - memcpy(blob->data + 3 + ((index.count + 1) * index.offSize), index.data, - index.offset[index.count] - 1); - } - blob->cursor = blob->size; - return blob; -} - -caryll_buffer *compile_charset(CFF_Charset cset) { - switch (cset.t) { - case CFF_CHARSET_ISOADOBE: - case CFF_CHARSET_EXPERT: - case CFF_CHARSET_EXPERTSUBSET: { - return bufnew(); - } - case CFF_CHARSET_FORMAT0: { - caryll_buffer *blob = bufnew(); - blob->size = 1 + cset.s * 2; - blob->data = calloc(blob->size, sizeof(uint8_t)); - blob->data[0] = 0; - for (uint32_t i = 0; i < cset.s; i++) - blob->data[1 + 2 * i] = cset.f0.glyph[i] / 256, - blob->data[2 + 2 * i] = cset.f0.glyph[i] % 256; - blob->cursor = blob->size; - return blob; - } - case CFF_CHARSET_FORMAT1: { - caryll_buffer *blob = bufnew(); - blob->size = 1 + cset.s * 3; - blob->data = calloc(blob->size, sizeof(uint8_t)); - blob->data[0] = 1; - for (uint32_t i = 0; i < cset.s; i++) - blob->data[1 + 3 * i] = cset.f1.range1[i].first / 256, - blob->data[2 + 3 * i] = cset.f1.range1[i].first % 256, - blob->data[3 + 3 * i] = cset.f1.range1[i].nleft; - return blob; - } - case CFF_CHARSET_FORMAT2: { - caryll_buffer *blob = bufnew(); - blob->size = 1 + cset.s * 4; - blob->data = calloc(blob->size, sizeof(uint8_t)); - blob->data[0] = 2; - for (uint32_t i = 0; i < cset.s; i++) - blob->data[1 + 4 * i] = cset.f2.range2[i].first / 256, - blob->data[2 + 4 * i] = cset.f2.range2[i].first % 256, - blob->data[3 + 4 * i] = cset.f2.range2[i].nleft / 256, - blob->data[4 + 4 * i] = cset.f2.range2[i].nleft % 256; - blob->cursor = blob->size; - return blob; - } - } - return NULL; -} - -caryll_buffer *compile_fdselect(CFF_FDSelect fd) { - switch (fd.t) { - case CFF_FDSELECT_UNSPECED: { - return bufnew(); - } - case CFF_FDSELECT_FORMAT0: { - caryll_buffer *blob = bufnew(); - blob->size = 1 + fd.s; - blob->data = calloc(blob->size, sizeof(uint8_t)); - for (uint16_t j = 0; j < fd.s; j++) { blob->data[j] = fd.f0.fds[j]; } - return blob; - } - case CFF_FDSELECT_FORMAT3: { - caryll_buffer *blob = bufnew(); - blob->size = 5 + fd.f3.nranges * 3; - blob->data = calloc(blob->size, sizeof(uint8_t)); - blob->data[0] = 3; - blob->data[1] = fd.f3.nranges / 256; - blob->data[2] = fd.f3.nranges % 256; - for (int i = 0; i < fd.f3.nranges; i++) - blob->data[3 + 3 * i] = fd.f3.range3[i].first / 256, - blob->data[4 + 3 * i] = fd.f3.range3[i].first % 256, - blob->data[5 + 3 * i] = fd.f3.range3[i].fd; - blob->data[blob->size - 2] = fd.f3.sentinel / 256; - blob->data[blob->size - 1] = fd.f3.sentinel % 256; - return blob; - } - default: { return NULL; } - } -} - void merge_cs2_operator(caryll_buffer *blob, int32_t val) { if (val >= 0x100) { bufnwrite8(blob, 2, val >> 8, val & 0xff); diff --git a/lib/libcff/charstring_il.c b/lib/libcff/charstring_il.c index 36c45509..174e0bcb 100644 --- a/lib/libcff/charstring_il.c +++ b/lib/libcff/charstring_il.c @@ -350,37 +350,41 @@ static uint8_t hhvvcurve_roll(charstring_il *il, uint32_t j) { } static uint32_t nextstop(charstring_il *il, uint32_t j) { uint32_t delta = 0; - for (uint32_t k = 0; k < il->length && il->instr[k].type == IL_ITEM_OPERAND; k++) { - delta += 1; - } + for (; j + delta < il->length && il->instr[j + delta].type == IL_ITEM_OPERAND; delta++) + ; return delta; } +#define ROLL_FALL(x) \ + if ((r = (x))) return r; +static uint8_t decideAdvance(charstring_il *il, uint32_t j, uint8_t optimizeLevel) { + uint8_t r = 0; + ROLL_FALL(zroll(il, j, op_rlineto, op_hlineto, 0, 1)); // rlineto -> hlineto + ROLL_FALL(zroll(il, j, op_rlineto, op_vlineto, 1, 0)); // rlineto -> vlineto + ROLL_FALL(zroll(il, j, op_rmoveto, op_hmoveto, 0, 1)); // rmoveto -> hmoveto + ROLL_FALL(zroll(il, j, op_rmoveto, op_vmoveto, 1, 0)); // rmoveto -> vmoveto + ROLL_FALL(zroll(il, j, op_rrcurveto, op_hvcurveto, 0, 1, 0, 0, 1, 0)); // rrcurveto->hvcurveto + ROLL_FALL(zroll(il, j, op_rrcurveto, op_vhcurveto, 1, 0, 0, 0, 0, 1)); // rrcurveto->vhcurveto + ROLL_FALL(zroll(il, j, op_rrcurveto, op_hhcurveto, 0, 1, 0, 0, 0, 1)); // rrcurveto->hhcurveto + ROLL_FALL(zroll(il, j, op_rrcurveto, op_vvcurveto, 1, 0, 0, 0, 1, 0)); // rrcurveto->vvcurveto + ROLL_FALL(opop_roll(il, j, op_rrcurveto, 6, op_rrcurveto, op_rrcurveto)); // rrcurveto roll + ROLL_FALL(opop_roll(il, j, op_rrcurveto, 2, op_rlineto, op_rcurveline)); // rcurveline roll + ROLL_FALL(opop_roll(il, j, op_rlineto, 6, op_rrcurveto, op_rlinecurve)); // rlinecurve roll + ROLL_FALL(opop_roll(il, j, op_rlineto, 2, op_rlineto, op_rlineto)); // rlineto roll + ROLL_FALL(opop_roll(il, j, op_hstemhm, 0, op_hintmask, op_hintmask)); // hintmask roll + ROLL_FALL(opop_roll(il, j, op_vstemhm, 0, op_hintmask, op_hintmask)); // hintmask roll + ROLL_FALL(opop_roll(il, j, op_hstemhm, 0, op_cntrmask, op_cntrmask)); // cntrmask roll + ROLL_FALL(opop_roll(il, j, op_vstemhm, 0, op_cntrmask, op_cntrmask)); // cntrmask roll + ROLL_FALL(hvlineto_roll(il, j)); // hlineto-vlineto roll + ROLL_FALL(hhvvcurve_roll(il, j)); // hhcurveto-vvcurveto roll + ROLL_FALL(hvvhcurve_roll(il, j)); // hvcurveto-vhcurveto roll + ROLL_FALL(nextstop(il, j)); // move to next stop for operand match + return 1; // nothing match +} -void glyph_il_peephole_optimization(charstring_il *il) { +void glyph_il_peephole_optimization(charstring_il *il, caryll_dump_options *dumpopts) { + if (!dumpopts->optimize_level) return; uint32_t j = 0; - while (j < il->length) { - j += zroll(il, j, op_rlineto, op_hlineto, 0, 1) // rlineto -> hlineto - || zroll(il, j, op_rlineto, op_vlineto, 1, 0) // rlineto -> vlineto - || zroll(il, j, op_rmoveto, op_hmoveto, 0, 1) // rmoveto -> hmoveto - || zroll(il, j, op_rmoveto, op_vmoveto, 1, 0) // rmoveto -> vmoveto - || zroll(il, j, op_rrcurveto, op_hvcurveto, 0, 1, 0, 0, 1, 0) // rrcurveto->hvcurveto - || zroll(il, j, op_rrcurveto, op_vhcurveto, 1, 0, 0, 0, 0, 1) // rrcurveto->vhcurveto - || zroll(il, j, op_rrcurveto, op_hhcurveto, 0, 1, 0, 0, 0, 1) // rrcurveto->hhcurveto - || zroll(il, j, op_rrcurveto, op_vvcurveto, 1, 0, 0, 0, 1, 0) // rrcurveto->vvcurveto - || opop_roll(il, j, op_rrcurveto, 6, op_rrcurveto, op_rrcurveto) // rrcurveto roll - || opop_roll(il, j, op_rrcurveto, 2, op_rlineto, op_rcurveline) // rcurveline roll - || opop_roll(il, j, op_rlineto, 6, op_rrcurveto, op_rlinecurve) // rlinecurve roll - || opop_roll(il, j, op_rlineto, 2, op_rlineto, op_rlineto) // rlineto roll - || opop_roll(il, j, op_hstemhm, 0, op_hintmask, op_hintmask) // hintmask roll - || opop_roll(il, j, op_vstemhm, 0, op_hintmask, op_hintmask) // hintmask roll - || opop_roll(il, j, op_hstemhm, 0, op_cntrmask, op_cntrmask) // cntrmask roll - || opop_roll(il, j, op_vstemhm, 0, op_cntrmask, op_cntrmask) // cntrmask roll - || hvlineto_roll(il, j) // hlineto-vlineto roll - || hhvvcurve_roll(il, j) // hhcurveto-vvcurveto roll - || hvvhcurve_roll(il, j) // hvcurveto-vhcurveto roll - || nextstop(il, j) // move to next stop - || 1; // nothing match - } + while (j < il->length) { j += decideAdvance(il, j, dumpopts->optimize_level); } } // IL to buffer conversion diff --git a/lib/libcff/charstring_il.h b/lib/libcff/charstring_il.h index 4c834dd2..9a81de0a 100644 --- a/lib/libcff/charstring_il.h +++ b/lib/libcff/charstring_il.h @@ -27,7 +27,7 @@ typedef struct { // basic ops charstring_il *compile_glyph_to_il(glyf_glyph *g, uint16_t defaultWidth, uint16_t nominalWidth); -void glyph_il_peephole_optimization(charstring_il *il); +void glyph_il_peephole_optimization(charstring_il *il, caryll_dump_options *dumpopts); caryll_buffer *il2blob(charstring_il *il); #endif diff --git a/lib/libcff/libcff.h b/lib/libcff/libcff.h index ba7a17ae..d0d3cc38 100644 --- a/lib/libcff/libcff.h +++ b/lib/libcff/libcff.h @@ -7,92 +7,12 @@ #include #include -// clang-format off -// CFF DICT Operators -enum { - op_version = 0x00, op_Copyright = 0x0c00, - op_Notice = 0x01, op_isFixedPitch = 0x0c01, - op_FullName = 0x02, op_ItalicAngle = 0x0c02, - op_FamilyName = 0x03, op_UnderlinePosition = 0x0c03, - op_Weight = 0x04, op_UnderlineThickness = 0x0c04, - op_FontBBox = 0x05, op_PaintType = 0x0c05, - op_BlueValues = 0x06, op_CharstringType = 0x0c06, - op_OtherBlues = 0x07, op_FontMatrix = 0x0c07, - op_FamilyBlues = 0x08, op_StrokeWidth = 0x0c08, - op_FamilyOtherBlues = 0x09, op_BlueScale = 0x0c09, - op_StdHW = 0x0a, op_BlueShift = 0x0c0a, - op_StdVW = 0x0b, op_BlueFuzz = 0x0c0b, - /* 0x0c escape */ op_StemSnapH = 0x0c0c, - op_UniqueID = 0x0d, op_StemSnapV = 0x0c0d, - op_XUID = 0x0e, op_ForceBold = 0x0c0e, - op_charset = 0x0f, /* 0x0c0f Reserved */ - op_Encoding = 0x10, /* 0x0c10 Reserved */ - op_CharStrings = 0x11, op_LanguageGroup = 0x0c11, - op_Private = 0x12, op_ExpansionFactor = 0x0c12, - op_Subrs = 0x13, op_initialRandomSeed = 0x0c13, - op_defaultWidthX = 0x14, op_SyntheicBase = 0x0c14, - op_nominalWidthX = 0x15, op_PostScript = 0x0c15, - op_BaseFontName = 0x0c16, - op_BaseFontBlend = 0x0c17, - /* 0x0c18 Reserved */ - /* 0x0c19 Reserved */ - /* 0x0c1a Reserved */ - /* 0x0c1b Reserved */ - /* 0x0c1c Reserved */ - /* 0x0c1d Reserved */ - op_ROS = 0x0c1e, - op_CIDFontVersion = 0x0c1f, - op_CIDFontRevision = 0x0c20, - op_CIDFontType = 0x0c21, - op_CIDCount = 0x0c22, - op_UIDBase = 0x0c23, - op_FDArray = 0x0c24, - op_FDSelect = 0x0c25, - op_FontName = 0x0c26, -}; - -// Type2 CharString Operators -enum { - /* 0x00 Reserved */ /* 0x0c00 Reserved */ - op_hstem = 0x01, /* 0x0c01 Reserved */ - /* 0x02 Reserved */ /* 0x0c02 Reserved */ - op_vstem = 0x03, op_and = 0x0c03, - op_vmoveto = 0x04, op_or = 0x0c04, - op_rlineto = 0x05, op_not = 0x0c05, - op_hlineto = 0x06, /* 0x0c06 Reserved */ - op_vlineto = 0x07, /* 0x0c07 Reserved */ - op_rrcurveto = 0x08, /* 0x0c08 Reserved */ - /* 0x09 Reserved */ op_abs = 0x0c09, - op_callsubr = 0x0a, op_add = 0x0c0a, - op_return = 0x0b, op_sub = 0x0c0b, - /* 0x0c escape */ op_div = 0x0c0c, - /* 0x0d Reserved */ /* 0x0c0d Reserved */ - op_endchar = 0x0e, op_neg = 0x0c0e, - /* 0x0f Reserved */ op_eq = 0x0c0f, - /* 0x10 Reserved */ /* 0x0c10 Reserved */ - /* 0x11 Reserved */ /* 0x0c11 Reserved */ - op_hstemhm = 0x12, op_drop = 0x0c12, - op_hintmask = 0x13, /* 0x0c13 Reserved */ - op_cntrmask = 0x14, op_put = 0x0c14, - op_rmoveto = 0x15, op_get = 0x0c15, - op_hmoveto = 0x16, op_ifelse = 0x0c16, - op_vstemhm = 0x17, op_random = 0x0c17, - op_rcurveline = 0x18, op_mul = 0x0c18, - op_rlinecurve = 0x19, /* 0x0c19 Reserved */ - op_vvcurveto = 0x1a, op_sqrt = 0x0c1a, - op_hhcurveto = 0x1b, op_dup = 0x0c1b, - /* 0x1c short int */ op_exch = 0x0c1c, - op_callgsubr = 0x1d, op_index = 0x0c1d, - op_vhcurveto = 0x1e, op_roll = 0x0c1e, - op_hvcurveto = 0x1f, /* 0x0c1f Reserved */ - /* 0x0c20 Reserved */ - /* 0x0c21 Reserved */ - op_hflex = 0x0c22, - op_flex = 0x0c23, - op_hflex1 = 0x0c24, - op_flex1 = 0x0c25, -}; -// clang-format on +#include "cff-util.h" +#include "cff-value.h" +#include "cff-index.h" +#include "cff-dict.h" +#include "cff-charset.h" +#include "cff-fdselect.h" // Limits of Type2 CharSrting enum { @@ -104,13 +24,6 @@ enum { type2_transient_array = 32, }; -typedef struct { - uint16_t count; - uint8_t offSize; - uint32_t *offset; - uint8_t *data; -} CFF_INDEX; - typedef struct { uint8_t major; uint8_t minor; @@ -156,73 +69,7 @@ typedef struct { }; } CFF_Encoding; -// CFF Charset Structures - -typedef struct { - uint8_t format; - uint16_t *glyph; -} charset_f0; - -typedef struct { - uint16_t first; - uint8_t nleft; -} charset_range1; - -typedef struct { - uint8_t format; - charset_range1 *range1; -} charset_f1; - -typedef struct { - uint16_t first; - uint16_t nleft; -} charset_range2; - -typedef struct { - uint8_t format; - charset_range2 *range2; -} charset_f2; - -typedef struct { - uint32_t t; - uint32_t s; // size - union { - charset_f0 f0; - charset_f1 f1; - charset_f2 f2; - }; -} CFF_Charset; - -// CFF FDSelect Structures - -typedef struct { - uint8_t format; - uint8_t *fds; -} fdselect_f0; - -typedef struct { - uint16_t first; - uint8_t fd; -} fdselect_range3; - -typedef struct { - uint8_t format; - uint16_t nranges; - fdselect_range3 *range3; - uint16_t sentinel; -} fdselect_f3; - -typedef struct { - uint32_t t; - uint32_t s; - union { - fdselect_f0 f0; - fdselect_f3 f3; - }; -} CFF_FDSelect; - // Predefined Encoding Types - enum { CFF_FONT_COMMON, CFF_FONT_CID, @@ -238,39 +85,6 @@ enum { CFF_ENC_UNSPECED, }; -enum { - CFF_CHARSET_ISOADOBE = 0, - CFF_CHARSET_UNSPECED = 0, - CFF_CHARSET_EXPERT = 1, - CFF_CHARSET_EXPERTSUBSET = 2, - CFF_CHARSET_FORMAT0 = 3, - CFF_CHARSET_FORMAT1 = 4, - CFF_CHARSET_FORMAT2 = 5, -}; - -enum { - CFF_FDSELECT_FORMAT0, - CFF_FDSELECT_FORMAT3, - CFF_FDSELECT_UNSPECED, -}; - -typedef enum { - CFF_OPERATOR = 1, - CS2_OPERATOR = 1, - CFF_INTEGER = 2, - CS2_OPERAND = 2, - CFF_DOUBLE = 3, - CS2_FRACTION = 3 -} CFF_Value_Type; - -typedef struct { - CFF_Value_Type t; - union { - int32_t i; - double d; - }; -} CFF_Value; - typedef struct { CFF_Value stack[256]; CFF_Value transient[32]; @@ -278,40 +92,23 @@ typedef struct { uint8_t stem; } CFF_Stack; -typedef struct { - uint32_t op; - uint32_t cnt; - CFF_Value *vals; -} CFF_Dict_Entry; - -typedef struct { - uint32_t count; - CFF_Dict_Entry *ents; -} CFF_Dict; - -typedef struct { - uint32_t count; - CFF_Dict *fdarray; - CFF_Dict *fprivate; -} CFF_Font_Dict; - typedef struct { uint8_t *raw_data; uint32_t raw_length; uint16_t cnt_glyph; CFF_Header head; - CFF_INDEX name; - CFF_INDEX top_dict; - CFF_INDEX string; - CFF_INDEX global_subr; + CFF_Index name; + CFF_Index top_dict; + CFF_Index string; + CFF_Index global_subr; CFF_Encoding encodings; // offset CFF_Charset charsets; // offset CFF_FDSelect fdselect; // offset - CFF_INDEX char_strings; // offset - CFF_INDEX font_dict; // offset - CFF_INDEX local_subr; // offset + CFF_Index char_strings; // offset + CFF_Index font_dict; // offset + CFF_Index local_subr; // offset } CFF_File; // Outline builder method table @@ -334,6 +131,8 @@ extern char *op_cff_name(uint32_t op); extern char *op_cs2_name(uint32_t op); uint8_t cs2_op_standard_arity(uint32_t op); +sds sdsget_cff_sid(uint16_t idx, CFF_Index str); + extern uint32_t decode_cff_token(uint8_t *start, CFF_Value *val); extern uint32_t decode_cs2_token(uint8_t *start, CFF_Value *val); @@ -346,43 +145,21 @@ extern caryll_buffer *encode_cff_real(double val); Writer */ +extern caryll_buffer *compile_offset(int32_t val); extern caryll_buffer *compile_header(void); -extern caryll_buffer *compile_index(CFF_INDEX index); extern caryll_buffer *compile_encoding(CFF_Encoding enc); -extern caryll_buffer *compile_charset(CFF_Charset cset); -extern caryll_buffer *compile_fdselect(CFF_FDSelect fd); - -extern void esrap_index(CFF_INDEX in); -extern void empty_index(CFF_INDEX *in); -extern void print_index(CFF_INDEX in); - -caryll_buffer *compile_offset(int32_t val); void merge_cs2_operator(caryll_buffer *blob, int32_t val); void merge_cs2_operand(caryll_buffer *blob, double val); void merge_cs2_special(caryll_buffer *blob, uint8_t val); -sds sdsget_cff_sid(uint16_t idx, CFF_INDEX str); +extern uint8_t parse_subr(uint16_t idx, uint8_t *raw, CFF_Index fdarray, CFF_FDSelect select, + CFF_Index *subr); +void parse_outline_callback(uint8_t *data, uint32_t len, CFF_Index gsubr, CFF_Index lsubr, + CFF_Stack *stack, void *outline, cff_outline_builder_interface methods); +// File extern CFF_File *CFF_stream_open(uint8_t *data, uint32_t len); extern void CFF_close(CFF_File *file); -extern uint8_t parse_subr(uint16_t idx, uint8_t *raw, CFF_INDEX fdarray, CFF_FDSelect select, - CFF_INDEX *subr); -void parse_outline_callback(uint8_t *data, uint32_t len, CFF_INDEX gsubr, CFF_INDEX lsubr, - CFF_Stack *stack, void *outline, cff_outline_builder_interface methods); - -extern CFF_INDEX *cff_index_init(void); -extern void cff_index_fini(CFF_INDEX *out); -CFF_INDEX *cff_buildindex_callback(void *context, uint32_t length, - caryll_buffer *(*fn)(void *, uint32_t)); - -void cff_dict_callback(uint8_t *data, uint32_t len, void *context, - void (*callback)(uint32_t op, uint8_t top, CFF_Value *stack, void *context)); - -extern double cffnum(CFF_Value v); - -void cff_delete_dict(CFF_Dict *dict); -caryll_buffer *compile_dict(CFF_Dict *dict); - #endif diff --git a/lib/support/util.h b/lib/support/util.h index 63829f9a..74761345 100644 --- a/lib/support/util.h +++ b/lib/support/util.h @@ -307,6 +307,7 @@ typedef struct { bool keep_modified_time; bool instr_as_bytes; char *glyph_name_prefix; + uint8_t optimize_level; } caryll_dump_options; #define MOVE /*move*/ diff --git a/lib/tables/CFF.c b/lib/tables/CFF.c index 89d3f0da..f7ec89ec 100644 --- a/lib/tables/CFF.c +++ b/lib/tables/CFF.c @@ -225,8 +225,8 @@ static void callback_extract_fd(uint32_t op, uint8_t top, CFF_Value *stack, void uint32_t privateLength = cffnum(stack[top - 2]); uint32_t privateOffset = cffnum(stack[top - 1]); meta->privateDict = caryll_new_CFF_private(); - cff_dict_callback(file->raw_data + privateOffset, privateLength, context, - callback_extract_private); + parse_dict_callback(file->raw_data + privateOffset, privateLength, context, + callback_extract_private); } break; // CID @@ -406,7 +406,7 @@ static void buildOutline(uint16_t i, cff_parse_context *context) { context->glyphs->glyphs[i] = g; uint64_t seed = context->seed; - CFF_INDEX localSubrs; + CFF_Index localSubrs; CFF_Stack stack; stack.index = 0; @@ -567,9 +567,9 @@ caryll_cff_parse_result caryll_read_CFF_and_glyf(caryll_packet packet) { context.meta = caryll_new_CFF(); // Extract data in TOP DICT - cff_dict_callback(cffFile->top_dict.data, - cffFile->top_dict.offset[1] - cffFile->top_dict.offset[0], &context, - callback_extract_fd); + parse_dict_callback(cffFile->top_dict.data, + cffFile->top_dict.offset[1] - cffFile->top_dict.offset[0], &context, + callback_extract_fd); if (!context.meta->fontName) { context.meta->fontName = sdsget_cff_sid(391, cffFile->name); @@ -582,9 +582,9 @@ caryll_cff_parse_result caryll_read_CFF_and_glyf(caryll_packet packet) { for (uint16_t j = 0; j < context.meta->fdArrayCount; j++) { context.meta->fdArray[j] = caryll_new_CFF(); context.fdArrayIndex = j; - cff_dict_callback(cffFile->font_dict.data + cffFile->font_dict.offset[j] - 1, - cffFile->font_dict.offset[j + 1] - cffFile->font_dict.offset[j], - &context, callback_extract_fd); + parse_dict_callback(cffFile->font_dict.data + cffFile->font_dict.offset[j] - 1, + cffFile->font_dict.offset[j + 1] - cffFile->font_dict.offset[j], + &context, callback_extract_fd); } } ret.meta = context.meta; @@ -812,9 +812,10 @@ table_CFF *caryll_CFF_from_json(json_value *root, caryll_dump_options *dumpopts) return fdFromJson(dump); } -static caryll_buffer *compile_glyph(glyf_glyph *g, uint16_t defaultWidth, uint16_t nominalWidthX) { +static caryll_buffer *compile_glyph(glyf_glyph *g, uint16_t defaultWidth, uint16_t nominalWidthX, + caryll_dump_options *dumpopts) { charstring_il *il = compile_glyph_to_il(g, defaultWidth, nominalWidthX); - glyph_il_peephole_optimization(il); + glyph_il_peephole_optimization(il, dumpopts); caryll_buffer *blob = il2blob(il); free(il->instr); free(il); @@ -825,14 +826,16 @@ typedef struct { table_glyf *glyf; uint16_t defaultWidth; uint16_t nominalWidthX; + caryll_dump_options *dumpopts; } cff_charstring_builder_context; static caryll_buffer *callback_makeglyph(void *_context, uint32_t j) { cff_charstring_builder_context *context = (cff_charstring_builder_context *)_context; - return compile_glyph(context->glyf->glyphs[j], context->defaultWidth, context->nominalWidthX); + return compile_glyph(context->glyf->glyphs[j], context->defaultWidth, context->nominalWidthX, + context->dumpopts); } static caryll_buffer *cff_make_charstrings(cff_charstring_builder_context *context) { if (context->glyf->numberGlyphs == 0) return bufnew(); - CFF_INDEX *charstring = + CFF_Index *charstring = cff_buildindex_callback(context, context->glyf->numberGlyphs, callback_makeglyph); caryll_buffer *final_blob = compile_index(*charstring); cff_index_fini(charstring); @@ -1012,7 +1015,7 @@ static caryll_buffer *cffstrings_to_indexblob(cff_sid_entry **h) { j++; } - CFF_INDEX *strings = cff_buildindex_callback(blobs, n, callback_makestringindex); + CFF_Index *strings = cff_buildindex_callback(blobs, n, callback_makestringindex); free(blobs); caryll_buffer *final_blob = compile_index(*strings); cff_index_fini(strings); @@ -1021,7 +1024,7 @@ static caryll_buffer *cffstrings_to_indexblob(cff_sid_entry **h) { } static caryll_buffer *cff_compile_nameindex(table_CFF *cff) { - CFF_INDEX *nameIndex = cff_index_init(); + CFF_Index *nameIndex = cff_index_init(); nameIndex->count = 1; nameIndex->offSize = 4; NEW_N(nameIndex->offset, 2); @@ -1108,7 +1111,7 @@ static caryll_buffer *cff_make_fdselect(table_CFF *cff, table_glyf *glyf) { fds->f3.sentinel = glyf->numberGlyphs; done:; caryll_buffer *e = compile_fdselect(*fds); - if (fds->t == CFF_FDSELECT_FORMAT3) FREE(fds->f3.range3); + close_fdselect(*fds); free(fds); return e; } @@ -1127,7 +1130,7 @@ static caryll_buffer *callback_makefd(void *_context, uint32_t i) { cff_delete_dict(fd); return blob; } -static CFF_INDEX *cff_make_fdarray(uint16_t fdArrayCount, table_CFF **fdArray, +static CFF_Index *cff_make_fdarray(uint16_t fdArrayCount, table_CFF **fdArray, cff_sid_entry **stringHash) { fdarray_compile_context context; context.fdArray = fdArray; @@ -1136,7 +1139,8 @@ static CFF_INDEX *cff_make_fdarray(uint16_t fdArrayCount, table_CFF **fdArray, return cff_buildindex_callback(&context, fdArrayCount, callback_makefd); } -static caryll_buffer *writeCFF_CIDKeyed(table_CFF *cff, table_glyf *glyf) { +static caryll_buffer *writeCFF_CIDKeyed(table_CFF *cff, table_glyf *glyf, + caryll_dump_options *dumpopts) { caryll_buffer *blob = bufnew(); // The Strings hashtable cff_sid_entry *stringHash = NULL; @@ -1158,7 +1162,7 @@ static caryll_buffer *writeCFF_CIDKeyed(table_CFF *cff, table_glyf *glyf) { caryll_buffer *e = cff_make_fdselect(cff, glyf); // FDArray - CFF_INDEX *fdArrayIndex = NULL; + CFF_Index *fdArrayIndex = NULL; caryll_buffer *r; if (cff->isCID) { fdArrayIndex = cff_make_fdarray(cff->fdArrayCount, cff->fdArray, &stringHash); @@ -1180,6 +1184,7 @@ static caryll_buffer *writeCFF_CIDKeyed(table_CFF *cff, table_glyf *glyf) { g2cContext.glyf = glyf; g2cContext.defaultWidth = cff->privateDict->defaultWidthX; g2cContext.nominalWidthX = cff->privateDict->nominalWidthX; + g2cContext.dumpopts = dumpopts; s = cff_make_charstrings(&g2cContext); } @@ -1277,6 +1282,6 @@ static caryll_buffer *writeCFF_CIDKeyed(table_CFF *cff, table_glyf *glyf) { return blob; } -caryll_buffer *caryll_write_CFF(caryll_cff_parse_result cffAndGlyf) { - return writeCFF_CIDKeyed(cffAndGlyf.meta, cffAndGlyf.glyphs); +caryll_buffer *caryll_write_CFF(caryll_cff_parse_result cffAndGlyf, caryll_dump_options *dumpopts) { + return writeCFF_CIDKeyed(cffAndGlyf.meta, cffAndGlyf.glyphs, dumpopts); } diff --git a/lib/tables/CFF.h b/lib/tables/CFF.h index 0c5a2ac7..64e22395 100644 --- a/lib/tables/CFF.h +++ b/lib/tables/CFF.h @@ -95,6 +95,6 @@ void caryll_delete_CFF(table_CFF *table); caryll_cff_parse_result caryll_read_CFF_and_glyf(caryll_packet packet); void caryll_CFF_to_json(table_CFF *table, json_value *root, caryll_dump_options *dumpopts); table_CFF *caryll_CFF_from_json(json_value *root, caryll_dump_options *dumpopts); -caryll_buffer *caryll_write_CFF(caryll_cff_parse_result cffAndGlyf); +caryll_buffer *caryll_write_CFF(caryll_cff_parse_result cffAndGlyf, caryll_dump_options *dumpopts); #endif diff --git a/lib/tables/OS_2.c b/lib/tables/OS_2.c index 2e73a49a..1e1d5d2b 100644 --- a/lib/tables/OS_2.c +++ b/lib/tables/OS_2.c @@ -229,7 +229,7 @@ table_OS_2 *caryll_OS_2_from_json(json_value *root, caryll_dump_options *dumpopt return os_2; } -caryll_buffer *caryll_write_OS_2(table_OS_2 *os_2) { +caryll_buffer *caryll_write_OS_2(table_OS_2 *os_2, caryll_dump_options *dumpopts) { caryll_buffer *buf = bufnew(); if (!os_2) return buf; bufwrite16b(buf, os_2->version); diff --git a/lib/tables/OS_2.h b/lib/tables/OS_2.h index 22769365..0eb46da9 100644 --- a/lib/tables/OS_2.h +++ b/lib/tables/OS_2.h @@ -51,6 +51,6 @@ table_OS_2 *caryll_new_OS_2(); table_OS_2 *caryll_read_OS_2(caryll_packet packet); void caryll_OS_2_to_json(table_OS_2 *table, json_value *root, caryll_dump_options *dumpopts); table_OS_2 *caryll_OS_2_from_json(json_value *root, caryll_dump_options *dumpopts); -caryll_buffer *caryll_write_OS_2(table_OS_2 *os_2); +caryll_buffer *caryll_write_OS_2(table_OS_2 *os_2, caryll_dump_options *dumpopts); #endif diff --git a/lib/tables/cmap.c b/lib/tables/cmap.c index f7ca1da2..23846dc8 100644 --- a/lib/tables/cmap.c +++ b/lib/tables/cmap.c @@ -307,7 +307,7 @@ caryll_buffer *caryll_write_cmap_format12(cmap_hash *cmap) { bufwrite32b(buf, nGroups); return buf; } -caryll_buffer *caryll_write_cmap(cmap_hash *cmap) { +caryll_buffer *caryll_write_cmap(cmap_hash *cmap, caryll_dump_options *dumpopts) { caryll_buffer *buf = bufnew(); if (!cmap || !*cmap) return buf; diff --git a/lib/tables/cmap.h b/lib/tables/cmap.h index 70629cd5..24074983 100644 --- a/lib/tables/cmap.h +++ b/lib/tables/cmap.h @@ -16,5 +16,5 @@ cmap_hash *caryll_read_cmap(caryll_packet packet); void caryll_delete_cmap(cmap_hash *table); void caryll_cmap_to_json(cmap_hash *table, json_value *root, caryll_dump_options *dumpopts); cmap_hash *caryll_cmap_from_json(json_value *root, caryll_dump_options *dumpopts); -caryll_buffer *caryll_write_cmap(cmap_hash *cmap); +caryll_buffer *caryll_write_cmap(cmap_hash *cmap, caryll_dump_options *dumpopts); #endif diff --git a/lib/tables/cvt.c b/lib/tables/cvt.c index 496af5c3..d6826d7d 100644 --- a/lib/tables/cvt.c +++ b/lib/tables/cvt.c @@ -58,7 +58,7 @@ table_cvt *caryll_cvt_from_json(json_value *root, const char *tag) { return t; } -caryll_buffer *caryll_write_cvt(table_cvt *table) { +caryll_buffer *caryll_write_cvt(table_cvt *table, caryll_dump_options *dumpopts) { caryll_buffer *buf = bufnew(); if (!table) return buf; for (uint16_t j = 0; j < table->length; j++) { bufwrite16b(buf, table->words[j]); } diff --git a/lib/tables/cvt.h b/lib/tables/cvt.h index f17143d8..e05633b4 100644 --- a/lib/tables/cvt.h +++ b/lib/tables/cvt.h @@ -5,7 +5,6 @@ #include #include - typedef struct { uint32_t length; uint16_t *words; @@ -15,6 +14,6 @@ void caryll_delete_cvt(table_cvt *table); void caryll_cvt_to_json(table_cvt *table, json_value *root, caryll_dump_options *dumpopts, const char *tag); table_cvt *caryll_cvt_from_json(json_value *root, const char *tag); -caryll_buffer *caryll_write_cvt(table_cvt *table); +caryll_buffer *caryll_write_cvt(table_cvt *table, caryll_dump_options *dumpopts); #endif diff --git a/lib/tables/fpgm-prep.c b/lib/tables/fpgm-prep.c index cb97568b..fd8962dd 100644 --- a/lib/tables/fpgm-prep.c +++ b/lib/tables/fpgm-prep.c @@ -54,7 +54,7 @@ table_fpgm_prep *caryll_fpgm_prep_from_json(json_value *root, const char *tag) { return t; } -caryll_buffer *caryll_write_fpgm_prep(table_fpgm_prep *table) { +caryll_buffer *caryll_write_fpgm_prep(table_fpgm_prep *table, caryll_dump_options *dumpopts) { caryll_buffer *buf = bufnew(); if (!table) return buf; bufwrite_bytes(buf, table->length, table->bytes); diff --git a/lib/tables/fpgm-prep.h b/lib/tables/fpgm-prep.h index 5e57b715..cc0ff421 100644 --- a/lib/tables/fpgm-prep.h +++ b/lib/tables/fpgm-prep.h @@ -16,6 +16,6 @@ void caryll_delete_fpgm_prep(table_fpgm_prep *table); void caryll_fpgm_prep_to_json(table_fpgm_prep *table, json_value *root, caryll_dump_options *dumpopts, const char *tag); table_fpgm_prep *caryll_fpgm_prep_from_json(json_value *root, const char *tag); -caryll_buffer *caryll_write_fpgm_prep(table_fpgm_prep *table); +caryll_buffer *caryll_write_fpgm_prep(table_fpgm_prep *table, caryll_dump_options *dumpopts); #endif diff --git a/lib/tables/gasp.c b/lib/tables/gasp.c index 7760ff27..4f7fb4ac 100644 --- a/lib/tables/gasp.c +++ b/lib/tables/gasp.c @@ -91,7 +91,7 @@ table_gasp *caryll_gasp_from_json(json_value *root) { return NULL; } -caryll_buffer *caryll_write_gasp(table_gasp *gasp) { +caryll_buffer *caryll_write_gasp(table_gasp *gasp, caryll_dump_options *dumpopts) { caryll_buffer *buf = bufnew(); if (!gasp || !gasp->records) return buf; bufwrite16b(buf, 1); diff --git a/lib/tables/gasp.h b/lib/tables/gasp.h index 5a466d53..69706cb3 100644 --- a/lib/tables/gasp.h +++ b/lib/tables/gasp.h @@ -22,5 +22,5 @@ void caryll_delete_gasp(table_gasp *table); table_gasp *caryll_read_gasp(caryll_packet packet); void caryll_gasp_to_json(table_gasp *table, json_value *root, caryll_dump_options *dumpopts); table_gasp *caryll_gasp_from_json(json_value *root); -caryll_buffer *caryll_write_gasp(table_gasp *table); +caryll_buffer *caryll_write_gasp(table_gasp *table, caryll_dump_options *dumpopts); #endif diff --git a/lib/tables/glyf.c b/lib/tables/glyf.c index e7d1f5fe..d16e5ca1 100644 --- a/lib/tables/glyf.c +++ b/lib/tables/glyf.c @@ -853,7 +853,7 @@ static void glyf_write_composite(glyf_glyph *g, caryll_buffer *gbuf) { } } void caryll_write_glyf(table_glyf *table, table_head *head, caryll_buffer *bufglyf, - caryll_buffer *bufloca) { + caryll_buffer *bufloca, caryll_dump_options *dumpopts) { caryll_buffer *gbuf = bufnew(); uint32_t *loca = malloc((table->numberGlyphs + 1) * sizeof(uint32_t)); diff --git a/lib/tables/glyf.h b/lib/tables/glyf.h index 95be9e53..b89e2463 100644 --- a/lib/tables/glyf.h +++ b/lib/tables/glyf.h @@ -136,6 +136,6 @@ void caryll_glyf_to_json(table_glyf *table, json_value *root, caryll_dump_option table_glyf *caryll_glyf_from_json(json_value *root, glyph_order_hash glyph_order, caryll_dump_options *dumpopts); void caryll_write_glyf(table_glyf *table, table_head *head, caryll_buffer *bufglyf, - caryll_buffer *bufloca); + caryll_buffer *bufloca, caryll_dump_options *dumpopts); #endif diff --git a/lib/tables/head.c b/lib/tables/head.c index 7c88dd92..c03aacd6 100644 --- a/lib/tables/head.c +++ b/lib/tables/head.c @@ -100,7 +100,7 @@ table_head *caryll_head_from_json(json_value *root, caryll_dump_options *dumpopt return head; } -caryll_buffer *caryll_write_head(table_head *head) { +caryll_buffer *caryll_write_head(table_head *head, caryll_dump_options *dumpopts) { caryll_buffer *buf = bufnew(); if (!head) return buf; bufwrite32b(buf, head->version); diff --git a/lib/tables/head.h b/lib/tables/head.h index 2d5ab57e..a0c7ddf8 100644 --- a/lib/tables/head.h +++ b/lib/tables/head.h @@ -29,6 +29,6 @@ table_head *caryll_new_head(); table_head *caryll_read_head(caryll_packet packet); void caryll_head_to_json(table_head *table, json_value *root, caryll_dump_options *dumpopts); table_head *caryll_head_from_json(json_value *root, caryll_dump_options *dumpopts); -caryll_buffer *caryll_write_head(table_head *head); +caryll_buffer *caryll_write_head(table_head *head, caryll_dump_options *dumpopts); #endif diff --git a/lib/tables/hhea.c b/lib/tables/hhea.c index d0adf00c..5124f21d 100644 --- a/lib/tables/hhea.c +++ b/lib/tables/hhea.c @@ -79,7 +79,7 @@ table_hhea *caryll_hhea_from_json(json_value *root, caryll_dump_options *dumpopt return hhea; } -caryll_buffer *caryll_write_hhea(table_hhea *hhea) { +caryll_buffer *caryll_write_hhea(table_hhea *hhea, caryll_dump_options *dumpopts) { caryll_buffer *buf = bufnew(); if (!hhea) return buf; bufwrite32b(buf, hhea->version); diff --git a/lib/tables/hhea.h b/lib/tables/hhea.h index 7d9d3426..f82ce045 100644 --- a/lib/tables/hhea.h +++ b/lib/tables/hhea.h @@ -26,6 +26,6 @@ table_hhea *caryll_new_hhea(); table_hhea *caryll_read_hhea(caryll_packet packet); void caryll_hhea_to_json(table_hhea *table, json_value *root, caryll_dump_options *dumpopts); table_hhea *caryll_hhea_from_json(json_value *root, caryll_dump_options *dumpopts); -caryll_buffer *caryll_write_hhea(table_hhea *hhea); +caryll_buffer *caryll_write_hhea(table_hhea *hhea, caryll_dump_options *dumpopts); #endif diff --git a/lib/tables/hmtx.c b/lib/tables/hmtx.c index d0903ca2..92359463 100644 --- a/lib/tables/hmtx.c +++ b/lib/tables/hmtx.c @@ -42,7 +42,8 @@ void caryll_delete_hmtx(table_hmtx *table) { free(table); } -caryll_buffer *caryll_write_hmtx(table_hmtx *hmtx, uint16_t count_a, uint16_t count_k) { +caryll_buffer *caryll_write_hmtx(table_hmtx *hmtx, uint16_t count_a, uint16_t count_k, + caryll_dump_options *dumpopts) { caryll_buffer *buf = bufnew(); if (!hmtx) return buf; if (hmtx->metrics) { diff --git a/lib/tables/hmtx.h b/lib/tables/hmtx.h index 08070396..93315cfe 100644 --- a/lib/tables/hmtx.h +++ b/lib/tables/hmtx.h @@ -20,6 +20,7 @@ typedef struct { table_hmtx *caryll_read_hmtx(caryll_packet packet, table_hhea *hhea, table_maxp *maxp); void caryll_delete_hmtx(table_hmtx *table); -caryll_buffer *caryll_write_hmtx(table_hmtx *table, uint16_t count_a, uint16_t count_k); +caryll_buffer *caryll_write_hmtx(table_hmtx *table, uint16_t count_a, uint16_t count_k, + caryll_dump_options *dumpopts); #endif diff --git a/lib/tables/maxp.c b/lib/tables/maxp.c index ab009e07..0e0ff367 100644 --- a/lib/tables/maxp.c +++ b/lib/tables/maxp.c @@ -90,7 +90,7 @@ table_maxp *caryll_maxp_from_json(json_value *root, caryll_dump_options *dumpopt return maxp; } -caryll_buffer *caryll_write_maxp(table_maxp *maxp) { +caryll_buffer *caryll_write_maxp(table_maxp *maxp, caryll_dump_options *dumpopts) { caryll_buffer *buf = bufnew(); if (!maxp) return buf; bufwrite32b(buf, maxp->version); diff --git a/lib/tables/maxp.h b/lib/tables/maxp.h index cc074dd9..99a902c2 100644 --- a/lib/tables/maxp.h +++ b/lib/tables/maxp.h @@ -27,5 +27,5 @@ table_maxp *caryll_new_maxp(); table_maxp *caryll_read_maxp(caryll_packet packet); void caryll_maxp_to_json(table_maxp *table, json_value *root, caryll_dump_options *dumpopts); table_maxp *caryll_maxp_from_json(json_value *root, caryll_dump_options *dumpopts); -caryll_buffer *caryll_write_maxp(table_maxp *maxp); +caryll_buffer *caryll_write_maxp(table_maxp *maxp, caryll_dump_options *dumpopts); #endif diff --git a/lib/tables/name.c b/lib/tables/name.c index ebd4ecdb..bc7e7333 100644 --- a/lib/tables/name.c +++ b/lib/tables/name.c @@ -135,7 +135,7 @@ table_name *caryll_name_from_json(json_value *root, caryll_dump_options *dumpopt } return name; } -caryll_buffer *caryll_write_name(table_name *name) { +caryll_buffer *caryll_write_name(table_name *name, caryll_dump_options *dumpopts) { caryll_buffer *buf = bufnew(); if (!name) return buf; bufwrite16b(buf, 0); diff --git a/lib/tables/name.h b/lib/tables/name.h index 578285bf..3840d229 100644 --- a/lib/tables/name.h +++ b/lib/tables/name.h @@ -23,5 +23,5 @@ table_name *caryll_read_name(caryll_packet packet); void caryll_delete_name(table_name *table); void caryll_name_to_json(table_name *table, json_value *root, caryll_dump_options *dumpopts); table_name *caryll_name_from_json(json_value *root, caryll_dump_options *dumpopts); -caryll_buffer *caryll_write_name(table_name *name); +caryll_buffer *caryll_write_name(table_name *name, caryll_dump_options *dumpopts); #endif diff --git a/lib/tables/otl/GDEF.c b/lib/tables/otl/GDEF.c index 9f79ad92..f1636fc0 100644 --- a/lib/tables/otl/GDEF.c +++ b/lib/tables/otl/GDEF.c @@ -221,7 +221,7 @@ static caryll_buffer *writeLigCarets(lig_caret_table *lc) { return buf; } -caryll_buffer *caryll_write_GDEF(table_GDEF *gdef) { +caryll_buffer *caryll_write_GDEF(table_GDEF *gdef, caryll_dump_options *dumpopts) { caryll_buffer *buf = bufnew(); bufwrite32b(buf, 0x10000); size_t offset = 12; diff --git a/lib/tables/otl/GDEF.h b/lib/tables/otl/GDEF.h index 68e22afc..ba84d9f9 100644 --- a/lib/tables/otl/GDEF.h +++ b/lib/tables/otl/GDEF.h @@ -27,6 +27,6 @@ void caryll_delete_GDEF(table_GDEF *gdef); table_GDEF *caryll_read_GDEF(caryll_packet packet); void caryll_GDEF_to_json(table_GDEF *gdef, json_value *root, caryll_dump_options *dumpopts); table_GDEF *caryll_GDEF_from_json(json_value *root, caryll_dump_options *dumpopts); -caryll_buffer *caryll_write_GDEF(table_GDEF *gdef); +caryll_buffer *caryll_write_GDEF(table_GDEF *gdef, caryll_dump_options *dumpopts); #endif diff --git a/lib/tables/otl/otl.c b/lib/tables/otl/otl.c index 3804d7ec..5dedbe17 100644 --- a/lib/tables/otl/otl.c +++ b/lib/tables/otl/otl.c @@ -889,7 +889,7 @@ static caryll_buffer *writeOTLScriptAndLanguages(table_otl *table) { return bufs; } -caryll_buffer *caryll_write_otl(table_otl *table) { +caryll_buffer *caryll_write_otl(table_otl *table, caryll_dump_options *dumpopts) { caryll_buffer *buf = bufnew(); bufwrite32b(buf, 0x10000); diff --git a/lib/tables/otl/otl.h b/lib/tables/otl/otl.h index e3a3a2c5..f1f5dd47 100644 --- a/lib/tables/otl/otl.h +++ b/lib/tables/otl/otl.h @@ -199,7 +199,7 @@ table_otl *caryll_read_otl(caryll_packet packet, uint32_t tag); void caryll_otl_to_json(table_otl *table, json_value *root, caryll_dump_options *dumpopts, const char *tag); table_otl *caryll_otl_from_json(json_value *root, caryll_dump_options *dumpopts, const char *tag); -caryll_buffer *caryll_write_otl(table_otl *table); +caryll_buffer *caryll_write_otl(table_otl *table, caryll_dump_options *dumpopts); #include "gsub-single.h" #include "gsub-multi.h" diff --git a/lib/tables/post.c b/lib/tables/post.c index 56931a4c..03f09e52 100644 --- a/lib/tables/post.c +++ b/lib/tables/post.c @@ -85,7 +85,7 @@ table_post *caryll_post_from_json(json_value *root, caryll_dump_options *dumpopt table_post *post = caryll_new_post(); json_value *table = NULL; if ((table = json_obj_get_type(root, "post", json_object))) { - if(dumpopts->short_post){ + if (dumpopts->short_post) { post->version = 0x30000; } else { post->version = caryll_to_fixed(json_obj_getnum(table, "version")); @@ -101,7 +101,8 @@ table_post *caryll_post_from_json(json_value *root, caryll_dump_options *dumpopt } return post; } -caryll_buffer *caryll_write_post(table_post *post, glyph_order_hash *glyphorder) { +caryll_buffer *caryll_write_post(table_post *post, glyph_order_hash *glyphorder, + caryll_dump_options *dumpopts) { caryll_buffer *buf = bufnew(); if (!post) return buf; bufwrite32b(buf, post->version); diff --git a/lib/tables/post.h b/lib/tables/post.h index dc8616ab..194b8b65 100644 --- a/lib/tables/post.h +++ b/lib/tables/post.h @@ -5,7 +5,6 @@ #include #include - typedef struct { // PostScript information f16dot16 version; @@ -25,6 +24,7 @@ table_post *caryll_read_post(caryll_packet packet); void caryll_delete_post(table_post *table); void caryll_post_to_json(table_post *table, json_value *root, caryll_dump_options *dumpopts); table_post *caryll_post_from_json(json_value *root, caryll_dump_options *dumpopts); -caryll_buffer *caryll_write_post(table_post *post, glyph_order_hash *glyphorder); +caryll_buffer *caryll_write_post(table_post *post, glyph_order_hash *glyphorder, + caryll_dump_options *dumpopts); #endif diff --git a/lib/tables/vhea.c b/lib/tables/vhea.c index 13a7320f..93859f4b 100644 --- a/lib/tables/vhea.c +++ b/lib/tables/vhea.c @@ -73,7 +73,7 @@ table_vhea *caryll_vhea_from_json(json_value *root, caryll_dump_options *dumpopt return vhea; } -caryll_buffer *caryll_write_vhea(table_vhea *vhea) { +caryll_buffer *caryll_write_vhea(table_vhea *vhea, caryll_dump_options *dumpopts) { caryll_buffer *buf = bufnew(); if (!vhea) return buf; bufwrite32b(buf, vhea->version); diff --git a/lib/tables/vhea.h b/lib/tables/vhea.h index 36a8473a..3721dbef 100644 --- a/lib/tables/vhea.h +++ b/lib/tables/vhea.h @@ -28,5 +28,5 @@ table_vhea *caryll_new_vhea(); table_vhea *caryll_read_vhea(caryll_packet packet); void caryll_vhea_to_json(table_vhea *table, json_value *root, caryll_dump_options *dumpopts); table_vhea *caryll_vhea_from_json(json_value *root, caryll_dump_options *dumpopts); -caryll_buffer *caryll_write_vhea(table_vhea *vhea); +caryll_buffer *caryll_write_vhea(table_vhea *vhea, caryll_dump_options *dumpopts); #endif diff --git a/lib/tables/vmtx.c b/lib/tables/vmtx.c index 4bfce629..da09e66d 100644 --- a/lib/tables/vmtx.c +++ b/lib/tables/vmtx.c @@ -42,7 +42,8 @@ void caryll_delete_vmtx(table_vmtx *table) { free(table); } -caryll_buffer *caryll_write_vmtx(table_vmtx *vmtx, uint16_t count_a, uint16_t count_k) { +caryll_buffer *caryll_write_vmtx(table_vmtx *vmtx, uint16_t count_a, uint16_t count_k, + caryll_dump_options *dumpopts) { caryll_buffer *buf = bufnew(); if (!vmtx) return buf; if (vmtx->metrics) { diff --git a/lib/tables/vmtx.h b/lib/tables/vmtx.h index eb95a431..577ef05e 100644 --- a/lib/tables/vmtx.h +++ b/lib/tables/vmtx.h @@ -19,6 +19,7 @@ typedef struct { table_vmtx *caryll_read_vmtx(caryll_packet packet, table_vhea *vhea, table_maxp *maxp); void caryll_delete_vmtx(table_vmtx *table); -caryll_buffer *caryll_write_vmtx(table_vmtx *table, uint16_t count_a, uint16_t count_k); +caryll_buffer *caryll_write_vmtx(table_vmtx *table, uint16_t count_a, uint16_t count_k, + caryll_dump_options *dumpopts); #endif diff --git a/makefile b/makefile index 8f5f417d..6fc2a1d1 100644 --- a/makefile +++ b/makefile @@ -1,4 +1,4 @@ -VERSION=0.2.2 +VERSION=0.2.3 ifndef PREMAKE5 PREMAKE5=premake5 @@ -76,22 +76,22 @@ ttfroundtriptest : cffroundtriptest : @bin/Release-x64/otfccdump tests/payload/WorkSans-Regular.otf -o build/roundtrip-WorkSans-Regular-1.json --pretty - @bin/Release-x64/otfccbuild build/roundtrip-WorkSans-Regular-1.json -o build/roundtrip-WorkSans-Regular-2.otf --keep-average-char-width --keep-modified-time + @bin/Release-x64/otfccbuild -O1 build/roundtrip-WorkSans-Regular-1.json -o build/roundtrip-WorkSans-Regular-2.otf --keep-average-char-width --keep-modified-time @bin/Release-x64/otfccdump build/roundtrip-WorkSans-Regular-2.otf -o build/roundtrip-WorkSans-Regular-3.json --pretty - @bin/Release-x64/otfccbuild build/roundtrip-WorkSans-Regular-3.json -o build/roundtrip-WorkSans-Regular-4.otf --keep-average-char-width --keep-modified-time + @bin/Release-x64/otfccbuild -O1 build/roundtrip-WorkSans-Regular-3.json -o build/roundtrip-WorkSans-Regular-4.otf --keep-average-char-width --keep-modified-time @bin/Release-x64/otfccdump build/roundtrip-WorkSans-Regular-4.otf -o build/roundtrip-WorkSans-Regular-5.json --pretty @node tests/ttf-roundtrip-test.js build/roundtrip-WorkSans-Regular-3.json build/roundtrip-WorkSans-Regular-5.json - @bin/Release-x64/otfccbuild tests/payload/WorkSans-Regular.json -o build/roundtrip-WorkSans-Regular-6.otf --keep-average-char-width --keep-modified-time + @bin/Release-x64/otfccbuild -O1 tests/payload/WorkSans-Regular.json -o build/roundtrip-WorkSans-Regular-6.otf --keep-average-char-width --keep-modified-time @bin/Release-x64/otfccdump build/roundtrip-WorkSans-Regular-6.otf -o build/roundtrip-WorkSans-Regular-7.json --pretty - @bin/Release-x64/otfccbuild build/roundtrip-WorkSans-Regular-7.json -o build/roundtrip-WorkSans-Regular-8.otf --keep-average-char-width --keep-modified-time + @bin/Release-x64/otfccbuild -O1 build/roundtrip-WorkSans-Regular-7.json -o build/roundtrip-WorkSans-Regular-8.otf --keep-average-char-width --keep-modified-time @bin/Release-x64/otfccdump build/roundtrip-WorkSans-Regular-8.otf -o build/roundtrip-WorkSans-Regular-9.json --pretty @node tests/ttf-roundtrip-test.js build/roundtrip-WorkSans-Regular-7.json build/roundtrip-WorkSans-Regular-9.json @bin/Release-x64/otfccdump tests/payload/Cormorant-Medium.otf -o build/roundtrip-Cormorant-Medium-1.json --pretty - @bin/Release-x64/otfccbuild build/roundtrip-Cormorant-Medium-1.json -o build/roundtrip-Cormorant-Medium-2.otf --keep-average-char-width --keep-modified-time + @bin/Release-x64/otfccbuild -O1 build/roundtrip-Cormorant-Medium-1.json -o build/roundtrip-Cormorant-Medium-2.otf --keep-average-char-width --keep-modified-time @bin/Release-x64/otfccdump build/roundtrip-Cormorant-Medium-2.otf -o build/roundtrip-Cormorant-Medium-3.json --pretty - @bin/Release-x64/otfccbuild build/roundtrip-Cormorant-Medium-3.json -o build/roundtrip-Cormorant-Medium-4.otf --keep-average-char-width --keep-modified-time + @bin/Release-x64/otfccbuild -O1 build/roundtrip-Cormorant-Medium-3.json -o build/roundtrip-Cormorant-Medium-4.otf --keep-average-char-width --keep-modified-time @bin/Release-x64/otfccdump build/roundtrip-Cormorant-Medium-4.otf -o build/roundtrip-Cormorant-Medium-5.json --pretty @node tests/ttf-roundtrip-test.js build/roundtrip-Cormorant-Medium-3.json build/roundtrip-Cormorant-Medium-5.json diff --git a/premake5.lua b/premake5.lua index d83e24d8..710c9be2 100644 --- a/premake5.lua +++ b/premake5.lua @@ -1,5 +1,37 @@ require "dep/premake-modules/xcode-alt" +function cbuildoptions() + filter "action:vs2015" + buildoptions { '/MP', '/Wall', '-Wno-unused-parameter', '-Qunused-arguments' } + filter { "action:vs2015", "platforms:x64" } + buildoptions {'-Wshorten-64-to-32'} + filter "action:gmake" + buildoptions { '-std=gnu11', '-Wall', '-Wno-multichar' } + filter "action:xcode4" + buildoptions { '-std=gnu11', '-Wall', '-Wno-multichar' } + filter {} +end + +function externcbuildoptions() + filter "action:vs2015" + buildoptions { '/MP', '-Qunused-arguments', '-Wno-unused-const-variable' } + filter "action:gmake" + buildoptions { '-std=gnu11', '-Wno-unused-const-variable', '-Wno-shorten-64-to-32' } + filter "action:xcode4" + buildoptions { '-std=gnu11', '-Wno-unused-const-variable', '-Wno-shorten-64-to-32' } + filter {} +end + +function cxxbuildoptions() + filter "action:vs2015" + buildoptions { '/MP', '-Qunused-arguments' } + filter "action:gmake" + buildoptions { '-std=gnu++11' } + filter "action:xcode4" + buildoptions { '-std=gnu++11' } + filter {} +end + -- Premake 5 configurations workspace "otfcc" configurations { "Debug", "Release" } @@ -9,7 +41,7 @@ workspace "otfcc" '_CARYLL_USE_PRE_SERIALIZED', 'MAIN_VER=0', "SECONDARY_VER=2", - "PATCH_VER=2" + "PATCH_VER=3" } location "build" @@ -19,20 +51,12 @@ workspace "otfcc" location "build/vs" toolset "msc-LLVM-vs2014" defines { '_CRT_SECURE_NO_WARNINGS', '_CRT_NONSTDC_NO_DEPRECATE' } - buildoptions { '/MP', '/Wall', '-Wno-unused-parameter', '-Wshorten-64-to-32', '-Qunused-arguments' } flags { "StaticRuntime" } includedirs { "dep/polyfill-msvc" } - filter {} - filter "action:gmake" location "build/gmake" - buildoptions { '-std=gnu11', '-Wall', '-Wno-multichar' } - filter {} - filter "action:xcode4" location "build/xcode" - --includedirs { "dep/extern", "dep/extern/**", "lib/**" } - buildoptions { '-std=gnu11', '-Wall', '-Wno-multichar' } filter {} filter "configurations:Debug" @@ -45,6 +69,7 @@ workspace "otfcc" project "deps" kind "StaticLib" language "C" + externcbuildoptions() files { "dep/extern/**.h", "dep/extern/**.c" @@ -54,12 +79,12 @@ project "deps" "dep/polyfill-msvc/**.h", "dep/polyfill-msvc/**.c" } - buildoptions { '-Wno-unused-const-variable', '-Wno-shorten-64-to-32' } filter {} project "libotfcc" kind "StaticLib" language "C" + cbuildoptions() files { "lib/**.h", "lib/**.c" @@ -68,6 +93,7 @@ project "libotfcc" project "otfccdump" kind "ConsoleApp" language "C" + cbuildoptions() targetdir "bin/%{cfg.buildcfg}-%{cfg.platform}" links { "libotfcc", "deps" } @@ -91,6 +117,7 @@ project "otfccdump" project "otfccbuild" kind "ConsoleApp" language "C" + cbuildoptions() targetdir "bin/%{cfg.buildcfg}-%{cfg.platform}" links { "libotfcc", "deps" } diff --git a/src/otfccbuild.c b/src/otfccbuild.c index b40fda4b..b17889ad 100644 --- a/src/otfccbuild.c +++ b/src/otfccbuild.c @@ -22,32 +22,38 @@ void printInfo() { fprintf(stdout, "This is otfccbuild, version %d.%d.%d.\n", MAIN_VER, SECONDARY_VER, PATCH_VER); } void printHelp() { - fprintf(stdout, - "\n" - "Usage : otfccbuild [OPTIONS] [input.json] -o output.[ttf|otf]\n\n" - " input.json : Path to input file. When absent the input will\n" - " be read from the STDIN.\n" - " -h, --help : Display this help message and exit.\n" - " -v, --version : Display version information and exit.\n" - " -o : Set output file path to .\n" - " --time : Time each substep.\n" - " --ignore-glyph-order : Ignore the glyph order information in the input.\n" - " --ignore-hints : Ignore the hinting information in the input.\n" - " --keep-average-char-width : Keep the OS/2.xAvgCharWidth value from the input\n" - " instead of stating the average width of glyphs. \n" - " Useful when creating a monospaced font.\n" - " --keep-modified-time : Keep the head.modified time in the json, instead\n" - " of using current time.\n" - " --short-post : Don't export glyph names in the result font. It \n" - " will reduce file size.\n" - " --dummy-DSIG : Include an empty DSIG table in the font. For\n" - " some Microsoft applications, a DSIG is required\n" - " to enable OpenType features.\n" - " --ship : Equivalent to the combination of these options:\n" - " * --ignore-glyph-order\n" - " * --short-post\n" - " * --dummy-dsig\n" - "\n"); + fprintf( + stdout, + "\n" + "Usage : otfccbuild [OPTIONS] [input.json] -o output.[ttf|otf]\n\n" + " input.json : Path to input file. When absent the input will\n" + " be read from the STDIN.\n" + " -h, --help : Display this help message and exit.\n" + " -v, --version : Display version information and exit.\n" + " -o : Set output file path to .\n" + " --time : Time each substep.\n" + " --ignore-glyph-order : Ignore the glyph order information in the input.\n" + " --ignore-hints : Ignore the hinting information in the input.\n" + " --keep-average-char-width : Keep the OS/2.xAvgCharWidth value from the input\n" + " instead of stating the average width of glyphs. \n" + " Useful when creating a monospaced font.\n" + " --keep-modified-time : Keep the head.modified time in the json, instead\n" + " of using current time.\n" + " --short-post : Don't export glyph names in the result font. It \n" + " will reduce file size.\n" + " --dummy-dsig, -s : Include an empty DSIG table in the font. For\n" + " some Microsoft applications, a DSIG is required\n" + " to enable OpenType features.\n" + " -O : Specify the level for optimization.\n" + " -O0 Turn off any optimization.\n" + " -O1 Default optimization.\n" + " -O2 More aggressive optimizations for web font. In\n" + " this level, the --ignore-glyph-order and\n" + " --short-post will be turned on.\n" + // " -O3 In this level, CFF Subroutinization will be\n" + // " enabled to compress more. Building font may be\n" + // " slower than -O2.\n" + "\n"); } void readEntireFile(char *inPath, char **_buffer, long *_length) { char *buffer = NULL; @@ -73,27 +79,16 @@ void readEntireFile(char *inPath, char **_buffer, long *_length) { } void readEntireStdin(char **_buffer, long *_length) { + freopen(NULL, "rb", stdin); static const long BUF_SIZE = 0x400; - static const long BUF_GROW = 0x100000; static const long BUF_MIN = 0x100; - long size = BUF_SIZE; - char *buffer = malloc(size); + char *buffer = malloc(BUF_SIZE); long length = 0; - long remain = size; + long remain = BUF_SIZE; while (!feof(stdin)) { if (remain <= BUF_MIN) { - remain += size; - if (size < BUF_GROW) { - size *= 2; - } else { - size += BUF_GROW; - } - char *p = realloc(buffer, size); - if (p == NULL) { - free(buffer); - exit(EXIT_FAILURE); - } - buffer = p; + remain += (length >> 1) & 0xFFFF; + buffer = realloc(buffer, length + remain); } fgets(buffer + length, remain, stdin); @@ -130,6 +125,7 @@ int main(int argc, char *argv[]) { int option_index = 0; int c; caryll_dump_options *dumpopts = calloc(1, sizeof(caryll_dump_options)); + dumpopts->optimize_level = 1; struct option longopts[] = {{"version", no_argument, NULL, 'v'}, {"help", no_argument, NULL, 'h'}, @@ -139,12 +135,13 @@ int main(int argc, char *argv[]) { {"keep-average-char-width", no_argument, NULL, 0}, {"keep-modified-time", no_argument, NULL, 0}, {"short-post", no_argument, NULL, 0}, - {"dummy-dsig", no_argument, NULL, 0}, + {"dummy-dsig", no_argument, NULL, 's'}, {"ship", no_argument, NULL, 0}, + {"optimize", required_argument, NULL, 'O'}, {"output", required_argument, NULL, 'o'}, {0, 0, 0, 0}}; - while ((c = getopt_long(argc, argv, "vhpo:n:", longopts, &option_index)) != (-1)) { + while ((c = getopt_long(argc, argv, "vhsO:o:", longopts, &option_index)) != (-1)) { switch (c) { case 0: /* If this option set a flag, do nothing else now. */ @@ -162,8 +159,6 @@ int main(int argc, char *argv[]) { dumpopts->ignore_glyph_order = true; } else if (strcmp(longopts[option_index].name, "short-post") == 0) { dumpopts->short_post = true; - } else if (strcmp(longopts[option_index].name, "dummy-dsig") == 0) { - dumpopts->dummy_DSIG = true; } else if (strcmp(longopts[option_index].name, "ship") == 0) { dumpopts->ignore_glyph_order = true; dumpopts->short_post = true; @@ -179,6 +174,16 @@ int main(int argc, char *argv[]) { case 'o': outputPath = sdsnew(optarg); break; + case 's': + dumpopts->dummy_DSIG = true; + break; + case 'O': + dumpopts->optimize_level = atoi(optarg); + if (dumpopts->optimize_level >= 2) { + dumpopts->short_post = true; + dumpopts->ignore_glyph_order = true; + } + break; } } if (show_help) {