summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/mfluadir/otfcc/src/luafunc.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/mfluadir/otfcc/src/luafunc.c')
-rw-r--r--Build/source/texk/web2c/mfluadir/otfcc/src/luafunc.c609
1 files changed, 609 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/src/luafunc.c b/Build/source/texk/web2c/mfluadir/otfcc/src/luafunc.c
new file mode 100644
index 00000000000..1ed14048438
--- /dev/null
+++ b/Build/source/texk/web2c/mfluadir/otfcc/src/luafunc.c
@@ -0,0 +1,609 @@
+#include "dep/json-builder.h"
+#include "otfcc/sfnt.h"
+#include "otfcc/font.h"
+#include "otfcc/sfnt-builder.h"
+#include "aliases.h"
+#include "platform.h"
+#include "stopwatch.h"
+
+#include <unistd.h>
+
+/* to reset the getopt_long */
+extern int optind;
+
+int otfcc_build(int b_argc, char *b_argv[]);
+int otfcc_dump(int b_argc, char *b_argv[]);
+
+
+
+#ifndef MAIN_VER
+#define MAIN_VER 0
+#endif
+#ifndef SECONDARY_VER
+#define SECONDARY_VER 0
+#endif
+#ifndef PATCH_VER
+#define PATCH_VER 0
+#endif
+
+static void dump_printInfo() {
+ fprintf(stdout, "This is dump, version %d.%d.%d.\n", MAIN_VER, SECONDARY_VER,
+ PATCH_VER);
+}
+
+static void build_printInfo() {
+ fprintf(stdout, "This is build, version %d.%d.%d.\n", MAIN_VER, SECONDARY_VER,
+ PATCH_VER);
+}
+
+static void dump_printHelp() {
+ fprintf(stdout,
+ "\n"
+ "Usage : dump [OPTIONS] input.[otf|ttf|ttc]\n\n"
+ " -h, --help : Display this help message and exit.\n"
+ " -v, --version : Display version information and exit.\n"
+ " -o <file> : Set output file path to <file>. When absent the dump\n"
+ " will be written to STDOUT.\n"
+ " -n <n>, --ttc-index <n> : Use the <n>th subfont within the input font.\n"
+ " --pretty : Prettify the output JSON.\n"
+ " --ugly : Force uglify the output JSON.\n"
+ " --verbose : Show more information when building.\n"
+ " -q, --quiet : Be silent when building.\n\n"
+ " --ignore-glyph-order : Do not export glyph order information.\n"
+ " --glyph-name-prefix pfx : Add a prefix to the glyph names.\n"
+ " --ignore-hints : Do not export hinting information.\n"
+ " --decimal-cmap : Export 'cmap' keys as decimal number.\n"
+ " --hex-cmap : Export 'cmap' keys as hex number (U+FFFF).\n"
+ " --name-by-hash : Name glyphs using its hash value.\n"
+ " --name-by-gid : Name glyphs using its glyph id.\n"
+ " --add-bom : Add BOM mark in the output. (It is default on Windows\n"
+ " when redirecting to another program. Use --no-bom to\n"
+ " turn it off.)\n"
+ "\n");
+}
+
+
+static void build_printHelp() {
+ fprintf(stdout,
+ "\n"
+ "Usage : build [OPTIONS] [input.json] -o output.[ttf|otf]\n\n"
+ " input.json : Path to input file. When absent the input will be\n"
+ " read from the STDIN.\n\n"
+ " -h, --help : Display this help message and exit.\n"
+ " -v, --version : Display version information and exit.\n"
+ " -o <file> : Set output file path to <file>.\n"
+ " -s, --dummy-dsig : Include an empty DSIG table in the font. For some\n"
+ " Microsoft applications, DSIG is required to enable\n"
+ " OpenType features.\n"
+ " -O<n> : Specify the level for optimization.\n"
+ " -O0 Turn off any optimization.\n"
+ " -O1 Default optimization.\n"
+ " -O2 More aggressive optimizations for web font. In this\n"
+ " level, the following options will be set:\n"
+ " --merge-features\n"
+ " --short-post\n"
+ " --subroutinize\n"
+ " -O3 Most aggressive opptimization strategy will be\n"
+ " used. In this level, these options will be set:\n"
+ " --force-cid\n"
+ " --ignore-glyph-order\n"
+ " --verbose : Show more information when building.\n"
+ " -q, --quiet : Be silent when building.\n\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-unicode-ranges : Keep the OS/2.ulUnicodeRange[1-4] as-is.\n"
+ " --keep-modified-time : Keep the head.modified time in the json, instead of\n"
+ " using current time.\n\n"
+ " --short-post : Don't export glyph names in the result font.\n"
+ " --ignore-glyph-order, -i : Ignore the glyph order information in the input.\n"
+ " --keep-glyph-order, -k : Keep the glyph order information in the input.\n"
+ " Use to preserve glyph order under -O2 and -O3.\n"
+ " --dont-ignore-glyph-order : Same as --keep-glyph-order.\n"
+ " --merge-features : Merge duplicate OpenType feature definitions.\n"
+ " --dont-merge-features : Keep duplicate OpenType feature definitions.\n"
+ " --merge-lookups : Merge duplicate OpenType lookups.\n"
+ " --dont-merge-lookups : Keep duplicate OpenType lookups.\n"
+ " --force-cid : Convert name-keyed CFF OTF into CID-keyed.\n"
+ " --subroutinize : Subroutinize CFF table.\n"
+ " --stub-cmap4 : Create a stub `cmap` format 4 subtable if format\n"
+ " 12 subtable is present.\n"
+ "\n");
+}
+
+
+static void build_readEntireFile(char *inPath, char **_buffer, long *_length) {
+ char *buffer = NULL;
+ long length = 0;
+ FILE *f = u8fopen(inPath, "rb");
+ if (!f) {
+ fprintf(stderr, "Cannot read JSON file \"%s\". Exit.\n", inPath);
+ exit(EXIT_FAILURE);
+ }
+ fseek(f, 0, SEEK_END);
+ length = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ buffer = malloc(length);
+ if (buffer) { fread(buffer, 1, length, f); }
+ fclose(f);
+
+ if (!buffer) {
+ fprintf(stderr, "Cannot read JSON file \"%s\". Exit.\n", inPath);
+ exit(EXIT_FAILURE);
+ }
+ *_buffer = buffer;
+ *_length = length;
+}
+
+
+int otfcc_build(int b_argc, char *b_argv[]) {
+ struct timespec begin;
+ time_now(&begin);
+
+ bool show_help = false;
+ bool show_version = false;
+ sds outputPath = NULL;
+ sds inPath = NULL;
+ int option_index = 0;
+ int c;
+
+ optind=0;
+ if ((b_argc==0)||(b_argv==NULL))
+ return 0;
+
+ otfcc_Options *options = otfcc_newOptions();
+ options->logger = otfcc_newLogger(otfcc_newStdErrTarget());
+ options->logger->indent(options->logger, "build");
+ otfcc_Options_optimizeTo(options, 1);
+
+ struct option longopts[] = {{"version", no_argument, NULL, 'v'},
+ {"help", no_argument, NULL, 'h'},
+ {"time", no_argument, NULL, 0},
+ {"ignore-glyph-order", no_argument, NULL, 0},
+ {"keep-glyph-order", no_argument, NULL, 0},
+ {"dont-ignore-glyph-order", no_argument, NULL, 0},
+ {"ignore-hints", no_argument, NULL, 0},
+ {"keep-average-char-width", no_argument, NULL, 0},
+ {"keep-unicode-ranges", no_argument, NULL, 0},
+ {"keep-modified-time", no_argument, NULL, 0},
+ {"merge-lookups", no_argument, NULL, 0},
+ {"merge-features", no_argument, NULL, 0},
+ {"dont-merge-lookups", no_argument, NULL, 0},
+ {"dont-merge-features", no_argument, NULL, 0},
+ {"short-post", no_argument, NULL, 0},
+ {"force-cid", no_argument, NULL, 0},
+ {"subroutinize", no_argument, NULL, 0},
+ {"stub-cmap4", no_argument, NULL, 0},
+ {"dummy-dsig", no_argument, NULL, 's'},
+ {"ship", no_argument, NULL, 0},
+ {"verbose", no_argument, NULL, 0},
+ {"quiet", no_argument, NULL, 0},
+ {"optimize", required_argument, NULL, 'O'},
+ {"output", required_argument, NULL, 'o'},
+ {0, 0, 0, 0}};
+
+ while ((c = getopt_long(b_argc, b_argv, "vhqskiO:o:", longopts, &option_index)) != (-1)) {
+ switch (c) {
+ case 0:
+ /* If this option set a flag, do nothing else now. */
+ if (longopts[option_index].flag != 0) {
+ break;
+ } else if (strcmp(longopts[option_index].name, "time") == 0) {
+ } else if (strcmp(longopts[option_index].name, "ignore-hints") == 0) {
+ options->ignore_hints = true;
+ } else if (strcmp(longopts[option_index].name, "keep-average-char-width") == 0) {
+ options->keep_average_char_width = true;
+ } else if (strcmp(longopts[option_index].name, "keep-unicode-ranges") == 0) {
+ options->keep_unicode_ranges = true;
+ } else if (strcmp(longopts[option_index].name, "keep-modified-time") == 0) {
+ options->keep_modified_time = true;
+ } else if (strcmp(longopts[option_index].name, "merge-features") == 0) {
+ options->merge_features = true;
+ } else if (strcmp(longopts[option_index].name, "merge-lookups") == 0) {
+ options->merge_lookups = true;
+ } else if (strcmp(longopts[option_index].name, "dont-merge-features") == 0) {
+ options->merge_features = false;
+ } else if (strcmp(longopts[option_index].name, "dont-merge-lookups") == 0) {
+ options->merge_lookups = false;
+ } else if (strcmp(longopts[option_index].name, "ignore-glyph-order") == 0) {
+ options->ignore_glyph_order = true;
+ } else if (strcmp(longopts[option_index].name, "keep-glyph-order") == 0) {
+ options->ignore_glyph_order = false;
+ } else if (strcmp(longopts[option_index].name, "dont-keep-glyph-order") == 0) {
+ options->ignore_glyph_order = false;
+ } else if (strcmp(longopts[option_index].name, "short-post") == 0) {
+ options->short_post = true;
+ } else if (strcmp(longopts[option_index].name, "force-cid") == 0) {
+ options->force_cid = true;
+ } else if (strcmp(longopts[option_index].name, "subroutinize") == 0) {
+ options->cff_doSubroutinize = true;
+ } else if (strcmp(longopts[option_index].name, "stub-cmap4") == 0) {
+ options->stub_cmap4 = true;
+ } else if (strcmp(longopts[option_index].name, "ship") == 0) {
+ options->ignore_glyph_order = true;
+ options->short_post = true;
+ options->dummy_DSIG = true;
+ } else if (strcmp(longopts[option_index].name, "verbose") == 0) {
+ options->verbose = true;
+ } else if (strcmp(longopts[option_index].name, "quiet") == 0) {
+ options->quiet = true;
+ }
+ break;
+ case 'v':
+ show_version = true;
+ break;
+ case 'h':
+ show_help = true;
+ break;
+ case 'k':
+ options->ignore_glyph_order = false;
+ break;
+ case 'i':
+ options->ignore_glyph_order = true;
+ break;
+ case 'o':
+ outputPath = sdsnew(optarg);
+ break;
+ case 's':
+ options->dummy_DSIG = true;
+ break;
+ case 'q':
+ options->quiet = true;
+ break;
+ case 'O':
+ otfcc_Options_optimizeTo(options, atoi(optarg));
+ break;
+ }
+ }
+ options->logger->setVerbosity(options->logger,
+ options->quiet ? 0 : options->verbose ? 0xFF : 1);
+ if (show_help) {
+ build_printInfo();
+ build_printHelp();
+ return 0;
+ }
+ if (show_version) {
+ build_printInfo();
+ return 0;
+ }
+
+ if (optind >= b_argc) {
+ inPath = NULL; // read from STDIN
+ } else {
+ inPath = sdsnew(b_argv[optind]); // read from file
+ }
+ if (!outputPath) {
+ logError("Unable to build OpenType font tile : output path not "
+ "specified. Exit.\n");
+ build_printHelp();
+ exit(EXIT_FAILURE);
+ }
+
+ char *buffer;
+ long length;
+ loggedStep("Load file") {
+ if (inPath) {
+ loggedStep("Load from file %s", inPath) {
+ build_readEntireFile(inPath, &buffer, &length);
+ sdsfree(inPath);
+ }
+ } else {
+ /*loggedStep("Load from stdin") {
+ build_readEntireStdin(&buffer, &length);
+ }*/
+ }
+ logStepTime;
+ }
+
+ json_value *jsonRoot = NULL;
+ loggedStep("Parse into JSON") {
+ jsonRoot = json_parse(buffer, length);
+ free(buffer);
+ logStepTime;
+ if (!jsonRoot) {
+ logError("Cannot parse JSON file \"%s\". Exit.\n", inPath);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ otfcc_Font *font;
+ loggedStep("Parse") {
+ otfcc_IFontBuilder *parser = otfcc_newJsonReader();
+ font = parser->read(jsonRoot, 0, options);
+ if (!font) {
+ logError("Cannot parse JSON file \"%s\" as a font. Exit.\n", inPath);
+ exit(EXIT_FAILURE);
+ }
+ parser->free(parser);
+ json_value_free(jsonRoot);
+ logStepTime;
+ }
+ loggedStep("Consolidate") {
+ otfcc_iFont.consolidate(font, options);
+ logStepTime;
+ }
+ loggedStep("Build") {
+ otfcc_IFontSerializer *writer = otfcc_newOTFWriter();
+ caryll_Buffer *otf = (caryll_Buffer *)writer->serialize(font, options);
+ loggedStep("Write to file") {
+ FILE *outfile = u8fopen(outputPath, "wb");
+ if (!outfile) {
+ logError("Cannot write to file \"%s\". Exit.\n", outputPath);
+ exit(EXIT_FAILURE);
+ }
+ fwrite(otf->data, sizeof(uint8_t), buflen(otf), outfile);
+ fclose(outfile);
+ }
+ logStepTime;
+ buffree(otf), writer->free(writer), otfcc_iFont.free(font), sdsfree(outputPath);
+ }
+ otfcc_deleteOptions(options);
+
+ return 0;
+}
+
+
+
+int otfcc_dump(int b_argc, char *b_argv[]) {
+ bool show_help = false;
+ bool show_version = false;
+ bool show_pretty = false;
+ bool show_ugly = false;
+ bool add_bom = false;
+ bool no_bom = false;
+ uint32_t ttcindex = 0;
+ struct option longopts[] = {{"version", no_argument, NULL, 'v'},
+ {"help", no_argument, NULL, 'h'},
+ {"pretty", no_argument, NULL, 'p'},
+ {"ugly", no_argument, NULL, 0},
+ {"time", no_argument, NULL, 0},
+ {"ignore-glyph-order", no_argument, NULL, 0},
+ {"ignore-hints", no_argument, NULL, 0},
+ {"hex-cmap", no_argument, NULL, 0},
+ {"decimal-cmap", no_argument, NULL, 0},
+ {"instr-as-bytes", no_argument, NULL, 0},
+ {"name-by-hash", no_argument, NULL, 0},
+ {"name-by-gid", no_argument, NULL, 0},
+ {"glyph-name-prefix", required_argument, NULL, 0},
+ {"verbose", no_argument, NULL, 0},
+ {"quiet", no_argument, NULL, 0},
+ {"add-bom", no_argument, NULL, 0},
+ {"no-bom", no_argument, NULL, 0},
+ {"output", required_argument, NULL, 'o'},
+ {"ttc-index", required_argument, NULL, 'n'},
+ {"debug-wait-on-start", no_argument, NULL, 0},
+ {0, 0, 0, 0}};
+
+ optind=0;
+ if ((b_argc==0)||(b_argv==NULL))
+ return 0;
+ otfcc_Options *options = otfcc_newOptions();
+ options->logger = otfcc_newLogger(otfcc_newStdErrTarget());
+ options->logger->indent(options->logger, "dump");
+ options->decimal_cmap = true;
+
+ int option_index = 0;
+ int c;
+
+ sds outputPath = NULL;
+ sds inPath = NULL;
+
+ while ((c = getopt_long(b_argc, b_argv, "vhqpio:n:", longopts, &option_index)) != (-1)) {
+ switch (c) {
+ case 0:
+ /* If this option set a flag, do nothing else now. */
+ if (longopts[option_index].flag != 0) {
+ break;
+ } else if (strcmp(longopts[option_index].name, "ugly") == 0) {
+ show_ugly = true;
+ } else if (strcmp(longopts[option_index].name, "time") == 0) {
+ } else if (strcmp(longopts[option_index].name, "add-bom") == 0) {
+ add_bom = true;
+ } else if (strcmp(longopts[option_index].name, "no-bom") == 0) {
+ no_bom = true;
+ } else if (strcmp(longopts[option_index].name, "ignore-glyph-order") == 0) {
+ options->ignore_glyph_order = true;
+ } else if (strcmp(longopts[option_index].name, "verbose") == 0) {
+ options->verbose = true;
+ } else if (strcmp(longopts[option_index].name, "quiet") == 0) {
+ options->quiet = true;
+ } else if (strcmp(longopts[option_index].name, "ignore-hints") == 0) {
+ options->ignore_hints = true;
+ } else if (strcmp(longopts[option_index].name, "decimal-cmap") == 0) {
+ options->decimal_cmap = true;
+ } else if (strcmp(longopts[option_index].name, "hex-cmap") == 0) {
+ options->decimal_cmap = false;
+ } else if (strcmp(longopts[option_index].name, "name-by-hash") == 0) {
+ options->name_glyphs_by_hash = true;
+ } else if (strcmp(longopts[option_index].name, "name-by-gid") == 0) {
+ options->name_glyphs_by_gid = true;
+ } else if (strcmp(longopts[option_index].name, "instr-as-bytes") == 0) {
+ options->instr_as_bytes = true;
+ } else if (strcmp(longopts[option_index].name, "glyph-name-prefix") == 0) {
+ options->glyph_name_prefix = strdup(optarg);
+ } else if (strcmp(longopts[option_index].name, "debug-wait-on-start") == 0) {
+ options->debug_wait_on_start = true;
+ }
+ break;
+ case 'v':
+ show_version = true;
+ break;
+ case 'i':
+ options->ignore_glyph_order = true;
+ break;
+ case 'h':
+ show_help = true;
+ break;
+ case 'p':
+ show_pretty = true;
+ break;
+ case 'o':
+ outputPath = sdsnew(optarg);
+ break;
+ case 'q':
+ options->quiet = true;
+ break;
+ case 'n':
+ ttcindex = atoi(optarg);
+ break;
+ }
+ }
+
+ if (options->debug_wait_on_start) { getchar(); }
+
+ options->logger->setVerbosity(options->logger,
+ options->quiet ? 0 : options->verbose ? 0xFF : 1);
+
+ if (show_help) {
+ dump_printInfo();
+ dump_printHelp();
+ return 0;
+ }
+ if (show_version) {
+ dump_printInfo();
+ return 0;
+ }
+
+ if (optind >= b_argc) {
+ logError("Expected argument for input file name.\n");
+ dump_printHelp();
+ exit(EXIT_FAILURE);
+ } else {
+ inPath = sdsnew(b_argv[optind]);
+ }
+
+ struct timespec begin;
+
+ time_now(&begin);
+
+ otfcc_SplineFontContainer *sfnt;
+ loggedStep("Read SFNT") {
+ logProgress("From file %s", inPath);
+ FILE *file = u8fopen(inPath, "rb");
+ sfnt = otfcc_readSFNT(file);
+ if (!sfnt || sfnt->count == 0) {
+ logError("Cannot read SFNT file \"%s\". Exit.\n", inPath);
+ exit(EXIT_FAILURE);
+ }
+ if (ttcindex >= sfnt->count) {
+ logError("Subfont index %d out of range for \"%s\" (0 -- %d). Exit.\n", ttcindex,
+ inPath, (sfnt->count - 1));
+ exit(EXIT_FAILURE);
+ }
+ logStepTime;
+ }
+
+ otfcc_Font *font;
+ loggedStep("Read Font") {
+ otfcc_IFontBuilder *reader = otfcc_newOTFReader();
+ font = reader->read(sfnt, ttcindex, options);
+ if (!font) {
+ logError("Font structure broken or corrupted \"%s\". Exit.\n", inPath);
+ exit(EXIT_FAILURE);
+ }
+ reader->free(reader);
+ if (sfnt) otfcc_deleteSFNT(sfnt);
+ logStepTime;
+ }
+ loggedStep("Consolidate") {
+ otfcc_iFont.consolidate(font, options);
+ logStepTime;
+ }
+ json_value *root;
+ loggedStep("Dump") {
+ otfcc_IFontSerializer *dumper = otfcc_newJsonWriter();
+ root = (json_value *)dumper->serialize(font, options);
+ if (!root) {
+ logError("Font structure broken or corrupted \"%s\". Exit.\n", inPath);
+ exit(EXIT_FAILURE);
+ }
+ logStepTime;
+ dumper->free(dumper);
+ }
+
+ char *buf;
+ size_t buflen;
+ loggedStep("Serialize to JSON") {
+ json_serialize_opts jsonOptions;
+ jsonOptions.mode = json_serialize_mode_packed;
+ jsonOptions.opts = 0;
+ jsonOptions.indent_size = 4;
+ if (show_pretty || (!outputPath && isatty(fileno(stdout)))) {
+ jsonOptions.mode = json_serialize_mode_multiline;
+ }
+ if (show_ugly) jsonOptions.mode = json_serialize_mode_packed;
+ buflen = json_measure_ex(root, jsonOptions);
+ buf = calloc(1, buflen);
+ json_serialize_ex(buf, root, jsonOptions);
+ logStepTime;
+ }
+
+ loggedStep("Output") {
+ if (outputPath) {
+ FILE *outputFile = u8fopen(outputPath, "wb");
+ if (!outputFile) {
+ logError("Cannot write to file \"%s\". Exit.", outputPath);
+ exit(EXIT_FAILURE);
+ }
+ if (add_bom) {
+ fputc(0xEF, outputFile);
+ fputc(0xBB, outputFile);
+ fputc(0xBF, outputFile);
+ }
+ size_t actualLen = buflen - 1;
+ while (!buf[actualLen])
+ actualLen -= 1;
+ fwrite(buf, sizeof(char), actualLen + 1, outputFile);
+ fclose(outputFile);
+ } else {
+#ifdef WIN32
+ if (isatty(fileno(stdout))) {
+ LPWSTR pwStr;
+ DWORD dwNum = widen_utf8(buf, &pwStr);
+ DWORD actual = 0;
+ DWORD written = 0;
+ const DWORD chunk = 0x10000;
+ while (written < dwNum) {
+ DWORD len = dwNum - written;
+ if (len > chunk) len = chunk;
+ WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), pwStr + written, len, &actual,
+ NULL);
+ written += len;
+ }
+ free(pwStr);
+ } else {
+ if (!no_bom) {
+ fputc(0xEF, stdout);
+ fputc(0xBB, stdout);
+ fputc(0xBF, stdout);
+ }
+ fputs(buf, stdout);
+ }
+#else
+ if (add_bom) {
+ fputc(0xEF, stdout);
+ fputc(0xBB, stdout);
+ fputc(0xBF, stdout);
+ }
+ fputs(buf, stdout);
+#endif
+ }
+ logStepTime;
+ }
+
+ loggedStep("Finalize") {
+ free(buf);
+ if (font) otfcc_iFont.free(font);
+ if (root) json_builder_free(root);
+ if (inPath) sdsfree(inPath);
+ if (outputPath) sdsfree(outputPath);
+ logStepTime;
+ }
+ otfcc_deleteOptions(options);
+
+ return 0;
+}
+
+
+