diff --git a/README.md b/README.md index 439b08c1..5664b6a7 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,7 @@ If you have [Ninja](https://ninja-build.org/) installed on your system, you can ```bash premake5 ninja cd build/ninja -ninja otfccdump_Release_x64 otfccbuild_Release_x64 +ninja otfccdump_release_x64 otfccbuild_release_x64 ``` Change the targets above when necessary. diff --git a/appveyor.yml b/appveyor.yml index f413778d..dd70ad73 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,19 +1,18 @@ environment: - VS_VERSION: vs2015 + VS_VERSION: vs2017 platform: - x64 +image: Visual Studio 2017 + configuration: - Release install: - set PATH=C:\msys64\usr\bin;%PATH% -before_build: - - call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 - build_script: - - dep\bin-win\premake5.exe vs2015 - - cmd /c _vcbuild64.bat /property:Configuration=Release + - dep\bin-win\premake5.exe vs2017 + - msbuild build\vs\otfcc.sln /m:%NUMBER_OF_PROCESSORS% /nr:false /nologo /verbosity:minimal /property:Configuration=Release - make -f quick.make test diff --git a/include/otfcc/options.h b/include/otfcc/options.h index cd458726..37832549 100644 --- a/include/otfcc/options.h +++ b/include/otfcc/options.h @@ -7,6 +7,7 @@ #include "logger.h" typedef struct { + bool debug_wait_on_start; bool ignore_glyph_order; bool ignore_hints; bool has_vertical_metrics; diff --git a/lib/bk/bkgraph.c b/lib/bk/bkgraph.c index 0bb84bb5..2c4b1415 100644 --- a/lib/bk/bkgraph.c +++ b/lib/bk/bkgraph.c @@ -234,10 +234,9 @@ static void dfs_attract_cells(bk_Block *b, bk_Graph *f, uint32_t *order, uint32_ return; } b->_visitstate = VISIT_GRAY; - for (uint32_t j = 0; j < b->length; j++) { + for (uint32_t j = b->length; j-- > 0;) { bk_Cell *cell = &(b->cells[j]); if (bk_cellIsPointer(cell) && cell->p) { dfs_attract_cells(cell->p, f, order, depth + 1); } - if (bk_cellIsPointer(cell) && cell->p) { dfs_attract_cells(cell->p, f, order, depth + 1); } } *order += 1; f->entries[b->_index].order = *order; diff --git a/lib/font/caryll-sfnt.c b/lib/font/caryll-sfnt.c index fc0875d6..e981d8dc 100644 --- a/lib/font/caryll-sfnt.c +++ b/lib/font/caryll-sfnt.c @@ -22,7 +22,8 @@ static void otfcc_read_packets(otfcc_SplineFontContainer *font, FILE *file) { for (uint32_t i = 0; i < font->packets[0].numTables; i++) { (void)fseek(file, font->packets[count].pieces[i].offset, SEEK_SET); - (void)fread(font->packets[count].pieces[i].data, font->packets[count].pieces[i].length, 1, file); + (void)fread(font->packets[count].pieces[i].data, font->packets[count].pieces[i].length, + 1, file); } } } diff --git a/lib/libcff/cff-parser.c b/lib/libcff/cff-parser.c index c85193ab..14ad9f2c 100644 --- a/lib/libcff/cff-parser.c +++ b/lib/libcff/cff-parser.c @@ -828,6 +828,12 @@ void cff_parseOutline(uint8_t *data, uint32_t len, cff_Index gsubr, cff_Index ls gsubr, lsubr, stack, outline, methods, options); break; } + default: { + logWarning("Warning: unknown operator %d occurs in Type 2 CharString. It " + "may caused by file corruption.", + val.i); + return; + } } break; case CS2_OPERAND: diff --git a/lib/support/base64/base64.c b/lib/support/base64/base64.c index ed454f0a..b57a0e15 100644 --- a/lib/support/base64/base64.c +++ b/lib/support/base64/base64.c @@ -9,8 +9,8 @@ uint8_t *base64_encode(const uint8_t *src, size_t len, size_t *out_len) { const uint8_t *end, *in; size_t olen; - olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */ - olen++; /* nul termination */ + olen = (len + 3 - 1) / 3 * 4; /* 3-byte blocks to 4-byte */ + olen++; /* nul termination */ out = __caryll_malloc(sizeof(uint8_t) * olen); if (out == NULL) return NULL; diff --git a/lib/support/bin-io.h b/lib/support/bin-io.h index 5d9f3c60..2df14b45 100644 --- a/lib/support/bin-io.h +++ b/lib/support/bin-io.h @@ -3,6 +3,7 @@ #include #include +#include #ifndef INLINE #ifdef _MSC_VER @@ -85,19 +86,31 @@ static INLINE uint64_t otfcc_endian_convert64(uint64_t i) { static INLINE uint16_t otfcc_get16u(FILE *file) { uint16_t tmp; - fread(&tmp, 2, 1, file); + size_t sizeRead = fread(&tmp, 2, 1, file); + if (!sizeRead) { + fprintf(stderr, "File corruption of terminated unexpectedly.\n"); + exit(EXIT_FAILURE); + } return otfcc_endian_convert16(tmp); } static INLINE uint32_t otfcc_get32u(FILE *file) { uint32_t tmp; - fread(&tmp, 4, 1, file); + size_t sizeRead = fread(&tmp, 4, 1, file); + if (!sizeRead) { + fprintf(stderr, "File corruption of terminated unexpectedly.\n"); + exit(EXIT_FAILURE); + } return otfcc_endian_convert32(tmp); } static INLINE uint64_t otfcc_get64u(FILE *file) { uint64_t tmp; - fread(&tmp, 8, 1, file); + size_t sizeRead = fread(&tmp, 8, 1, file); + if (!sizeRead) { + fprintf(stderr, "File corruption of terminated unexpectedly.\n"); + exit(EXIT_FAILURE); + } return otfcc_endian_convert64(tmp); } diff --git a/lib/support/unicodeconv/unicodeconv.c b/lib/support/unicodeconv/unicodeconv.c index 00f42cfa..a2df6452 100644 --- a/lib/support/unicodeconv/unicodeconv.c +++ b/lib/support/unicodeconv/unicodeconv.c @@ -37,7 +37,7 @@ sds utf16le_to_utf8(const uint8_t *inb, int inlenb) { } } in = (uint16_t *)inb; - sds out = sdsnewlen("", bytesNeeded); + sds out = sdsnewlen(NULL, bytesNeeded); sds out0 = out; while (in < inend) { @@ -120,7 +120,7 @@ sds utf16be_to_utf8(const uint8_t *inb, int inlenb) { } } in = (uint16_t *)inb; - sds out = sdsnewlen("", bytesNeeded); + sds out = sdsnewlen(NULL, bytesNeeded); sds out0 = out; while (in < inend) { diff --git a/lib/table/CFF.c b/lib/table/CFF.c index f7500718..aff6dbd1 100644 --- a/lib/table/CFF.c +++ b/lib/table/CFF.c @@ -1035,8 +1035,10 @@ static cff_Dict *cff_make_fd_dict(table_CFF *fd, cff_sid_entry **h) { cffdict_input(dict, op_UnderlineThickness, cff_DOUBLE, 1, fd->underlineThickness); cffdict_input(dict, op_StrokeWidth, cff_DOUBLE, 1, fd->strokeWidth); if (fd->fontMatrix) { - cffdict_input(dict, op_FontMatrix, cff_DOUBLE, 6, fd->fontMatrix->a, fd->fontMatrix->b, - fd->fontMatrix->c, fd->fontMatrix->d, fd->fontMatrix->x, fd->fontMatrix->y); + cffdict_input(dict, op_FontMatrix, cff_DOUBLE, 6, + fd->fontMatrix->a, fd->fontMatrix->b, + fd->fontMatrix->c, fd->fontMatrix->d, + iVQ.getStill(fd->fontMatrix->x), iVQ.getStill(fd->fontMatrix->y)); } // CID specific diff --git a/lib/table/OS_2.c b/lib/table/OS_2.c index bc5d0744..91f35acc 100644 --- a/lib/table/OS_2.c +++ b/lib/table/OS_2.c @@ -18,9 +18,9 @@ table_OS_2 *otfcc_readOS_2(const otfcc_Packet packet, const otfcc_Options *optio if (length < 2) goto OS_2_CORRUPTED; os_2 = table_iOS_2.create(); os_2->version = read_16u(data); - // version 1 - if (os_2->version == 0 || (os_2->version >= 1 && length < 86)) goto OS_2_CORRUPTED; - if (os_2->version >= 1) { + // version 0 (Apple's TrueType) + if (length < 68) goto OS_2_CORRUPTED; + { os_2->xAvgCharWidth = read_16u(data + 2); os_2->usWeightClass = read_16u(data + 4); os_2->usWidthClass = read_16u(data + 6); @@ -45,11 +45,18 @@ table_OS_2 *otfcc_readOS_2(const otfcc_Packet packet, const otfcc_Options *optio os_2->fsSelection = read_16u(data + 62); os_2->usFirstCharIndex = read_16u(data + 64); os_2->usLastCharIndex = read_16u(data + 66); + } + // version 0 (OpenType) + if (length >= 78) { os_2->sTypoAscender = read_16s(data + 68); os_2->sTypoDescender = read_16s(data + 70); os_2->sTypoLineGap = read_16s(data + 72); os_2->usWinAscent = read_16u(data + 74); os_2->usWinDescent = read_16u(data + 76); + } + // version 1 + if (os_2->version >= 1 && length < 86) goto OS_2_CORRUPTED; + if (os_2->version >= 1) { os_2->ulCodePageRange1 = read_32u(data + 78); os_2->ulCodePageRange2 = read_32u(data + 82); } diff --git a/lib/table/cmap.c b/lib/table/cmap.c index e2cf5757..164ba757 100644 --- a/lib/table/cmap.c +++ b/lib/table/cmap.c @@ -231,12 +231,15 @@ static void readFormat14(font_file_pointer start, uint32_t lengthLimit, table_cm } } -static void readCmapMappingTable(font_file_pointer start, uint32_t lengthLimit, table_cmap *cmap) { +static void readCmapMappingTable(font_file_pointer start, uint32_t lengthLimit, table_cmap *cmap, + tableid_t requiredFormat) { uint16_t format = read_16u(start); - if (format == 4) { - readFormat4(start, lengthLimit, cmap); - } else if (format == 12) { - readFormat12(start, lengthLimit, cmap); + if (format == requiredFormat) { + if (format == 4) { + readFormat4(start, lengthLimit, cmap); + } else if (format == 12) { + readFormat12(start, lengthLimit, cmap); + } } } @@ -264,6 +267,10 @@ static INLINE bool isValidCmapEncoding(uint16_t platform, uint16_t encoding) { (platform == 3 && encoding == 10); } +// Note: we do not support Apple's format 0 subtable +// since we not never support legacy fonts. +const tableid_t formatPriorities[] = {12, 4, 0}; + // OTFCC will not support all `cmap` mappings. table_cmap *otfcc_readCmap(const otfcc_Packet packet, const otfcc_Options *options) { // the map is a reference to a hash table @@ -277,18 +284,21 @@ table_cmap *otfcc_readCmap(const otfcc_Packet packet, const otfcc_Options *optio uint16_t numTables = read_16u(data + 2); if (length < 4 + 8 * numTables) goto CMAP_CORRUPTED; - // step 1 : read format 4 and 12 - for (uint16_t j = 0; j < numTables; j++) { - uint16_t platform = read_16u(data + 4 + 8 * j); - uint16_t encoding = read_16u(data + 4 + 8 * j + 2); - if (!isValidCmapEncoding(platform, encoding)) continue; - - uint32_t tableOffset = read_32u(data + 4 + 8 * j + 4); - readCmapMappingTable(data + tableOffset, length - tableOffset, cmap); - }; + // step 1 : read format 12. The results are prioritized + for (size_t kSubtableType = 0; formatPriorities[kSubtableType]; kSubtableType++) { + for (uint16_t j = 0; j < numTables; j++) { + uint16_t platform = read_16u(data + 4 + 8 * j); + uint16_t encoding = read_16u(data + 4 + 8 * j + 2); + if (!isValidCmapEncoding(platform, encoding)) continue; + + uint32_t tableOffset = read_32u(data + 4 + 8 * j + 4); + readCmapMappingTable(data + tableOffset, length - tableOffset, cmap, + formatPriorities[kSubtableType]); + }; + } HASH_SORT(cmap->unicodes, by_unicode); - // step2 : read format 14 + // step 3 : read format 14 for (uint16_t j = 0; j < numTables; j++) { uint16_t platform = read_16u(data + 4 + 8 * j); uint16_t encoding = read_16u(data + 4 + 8 * j + 2); @@ -538,6 +548,16 @@ static caryll_Buffer *otfcc_buildCmap_format4(const table_cmap *cmap) { return buf; } +static caryll_Buffer *otfcc_tryBuildCmap_format4(const table_cmap *cmap) { + caryll_Buffer *buf = otfcc_buildCmap_format4(cmap); + if (buflen(buf) > UINT16_MAX) { + // this cmap subtable is broken + buffree(buf); + return NULL; + } else + return buf; +} + static caryll_Buffer *otfcc_buildCmap_format12(const table_cmap *cmap) { caryll_Buffer *buf = bufnew(); bufwrite16b(buf, 12); @@ -705,18 +725,23 @@ caryll_Buffer *otfcc_buildCmap(const table_cmap *cmap, const otfcc_Options *opti if (!cmap || !cmap->unicodes) return NULL; cmap_Entry *entry; - bool hasSMP = false; + bool requiresFormat12 = false; bool hasUVS = cmap->uvs && (HASH_COUNT(cmap->uvs) > 0); foreach_hash(entry, cmap->unicodes) { - if (entry->unicode > 0xFFFF) { hasSMP = true; } + if (entry->unicode > 0xFFFF) { requiresFormat12 = true; } } - uint8_t nTables = hasSMP ? 4 : 2; + + caryll_Buffer *format4 = NULL; + if (!requiresFormat12 || !options->stub_cmap4) { + format4 = otfcc_tryBuildCmap_format4(cmap); + if (!format4) + requiresFormat12 = true; + } + + uint8_t nTables = requiresFormat12 ? 4 : 2; if (hasUVS) nTables += 1; - caryll_Buffer *format4; - if (!hasSMP || !options->stub_cmap4) { - format4 = otfcc_buildCmap_format4(cmap); - } else { + if (!format4) { // Write a dummy format4 = bufnew(); bufwrite16b(format4, 4); // format @@ -746,7 +771,7 @@ caryll_Buffer *otfcc_buildCmap(const table_cmap *cmap, const otfcc_Options *opti b16, 3, // BMP p32, bk_newBlockFromBufferCopy(format4), // table bkover); - if (hasSMP) { + if (requiresFormat12) { bk_push(root, b16, 0, // unicode b16, 4, // full p32, bk_newBlockFromBufferCopy(format12), // table @@ -763,7 +788,7 @@ caryll_Buffer *otfcc_buildCmap(const table_cmap *cmap, const otfcc_Options *opti b16, 1, // Unicode BMP p32, bk_newBlockFromBufferCopy(format4), // table bkover); - if (hasSMP) { + if (requiresFormat12) { bk_push(root, b16, 3, // Windows b16, 10, // Unicode Full p32, bk_newBlockFromBufferCopy(format12), // table diff --git a/lib/table/glyf.h b/lib/table/glyf.h index ee7d0c6d..3183cb71 100644 --- a/lib/table/glyf.h +++ b/lib/table/glyf.h @@ -51,7 +51,9 @@ typedef enum { WE_HAVE_A_TWO_BY_TWO = (1 << 7), WE_HAVE_INSTRUCTIONS = (1 << 8), USE_MY_METRICS = (1 << 9), - OVERLAP_COMPOUND = (1 << 10) + OVERLAP_COMPOUND = (1 << 10), + SCALED_COMPONENT_OFFSET = (1 << 11), + UNSCALED_COMPONENT_OFFSET = (1 << 12) } glyf_reference_flag; typedef enum { MASK_ON_CURVE = 1 } glyf_oncurve_mask; diff --git a/lib/table/glyf/build.c b/lib/table/glyf/build.c index 71fc70bb..5fe61e71 100644 --- a/lib/table/glyf/build.c +++ b/lib/table/glyf/build.c @@ -152,6 +152,7 @@ static void glyf_build_composite(const glyf_Glyph *g, caryll_Buffer *gbuf) { } if (r->roundToGrid) flags |= ROUND_XY_TO_GRID; if (r->useMyMetrics) flags |= USE_MY_METRICS; + flags |= UNSCALED_COMPONENT_OFFSET; bufwrite16b(gbuf, flags); bufwrite16b(gbuf, r->glyph.index); if (flags & ARG_1_AND_2_ARE_WORDS) { diff --git a/lib/table/glyf/read.c b/lib/table/glyf/read.c index 80c9b060..8976dde7 100644 --- a/lib/table/glyf/read.c +++ b/lib/table/glyf/read.c @@ -181,11 +181,15 @@ static glyf_Glyph *otfcc_read_composite_glyph(font_file_pointer start, ref.a = otfcc_from_f2dot14(read_16s(start + offset)); ref.b = otfcc_from_f2dot14(read_16s(start + offset + 2)); ref.c = otfcc_from_f2dot14(read_16s(start + offset + 4)); - ref.d = otfcc_from_f2dot14(read_16s(start + offset + 2)); + ref.d = otfcc_from_f2dot14(read_16s(start + offset + 6)); offset += 8; } ref.roundToGrid = flags & ROUND_XY_TO_GRID; ref.useMyMetrics = flags & USE_MY_METRICS; + if (flags & SCALED_COMPONENT_OFFSET && + (flags & WE_HAVE_AN_X_AND_Y_SCALE || flags & WE_HAVE_A_TWO_BY_TWO)) { + logWarning("glyf: SCALED_COMPONENT_OFFSET is not supported.") + } if (flags & WE_HAVE_INSTRUCTIONS) { glyphHasInstruction = true; } glyf_iReferenceList.push(&g->references, ref); } while (flags & MORE_COMPONENTS); diff --git a/lib/table/otl/build.c b/lib/table/otl/build.c index f8e9275b..15873951 100644 --- a/lib/table/otl/build.c +++ b/lib/table/otl/build.c @@ -134,7 +134,8 @@ static bk_Block *writeOTLLookups(const table_OTL *table, const otfcc_Options *op logNotice("Lookup %s is empty.\n", table->lookups.items[j]->name); } otl_Lookup *lookup = table->lookups.items[j]; - bool useExtendedForIt = useExtended || preferExtForThisLut[j]; + const bool canBeContextual = otfcc_chainingLookupIsContextualLookup(lookup); + const bool useExtendedForIt = useExtended || preferExtForThisLut[j]; if (useExtendedForIt) { logNotice("[OTFCC-fea] Using extended OpenType table layout for %s/%s.\n", tag, lookup->name); @@ -149,19 +150,22 @@ static bk_Block *writeOTLLookups(const table_OTL *table, const otfcc_Options *op : (lookup->type > otl_type_gpos_unknown ? lookup->type - otl_type_gpos_unknown : lookup->type > otl_type_gsub_unknown ? lookup->type - otl_type_gsub_unknown - : 0); + : 0) - + (canBeContextual ? 1 : 0); bk_Block *blk = bk_new_Block(b16, lookupType, // LookupType b16, lookup->flags, // LookupFlag b16, subtableQuantity[j], // SubTableCount bkover); + for (tableid_t k = 0; k < subtableQuantity[j]; k++) { if (useExtendedForIt) { - uint16_t extensionLookupType = lookup->type > otl_type_gpos_unknown - ? lookup->type - otl_type_gpos_unknown - : lookup->type > otl_type_gsub_unknown - ? lookup->type - otl_type_gsub_unknown - : 0; + uint16_t extensionLookupType = (lookup->type > otl_type_gpos_unknown + ? lookup->type - otl_type_gpos_unknown + : lookup->type > otl_type_gsub_unknown + ? lookup->type - otl_type_gsub_unknown + : 0) - + (canBeContextual ? 1 : 0); bk_Block *stub = bk_new_Block(b16, 1, // format diff --git a/lib/table/otl/subtables/chaining.h b/lib/table/otl/subtables/chaining.h index 494c6db9..a7b14ac8 100644 --- a/lib/table/otl/subtables/chaining.h +++ b/lib/table/otl/subtables/chaining.h @@ -17,9 +17,12 @@ otl_Subtable *otl_read_contextual(const font_file_pointer data, uint32_t tableLe json_value *otl_dump_chaining(const otl_Subtable *_subtable); otl_Subtable *otl_parse_chaining(const json_value *_subtable, const otfcc_Options *options); caryll_Buffer *otfcc_build_chaining(const otl_Subtable *_subtable); +caryll_Buffer *otfcc_build_contextual(const otl_Subtable *_subtable); tableid_t otfcc_classifiedBuildChaining(const otl_Lookup *lookup, OUT caryll_Buffer ***subtableBuffers, MODIFY size_t *lastOffset); +bool otfcc_chainingLookupIsContextualLookup(const otl_Lookup *lookup); + #endif diff --git a/lib/table/otl/subtables/chaining/build.c b/lib/table/otl/subtables/chaining/build.c index dda273cc..ffe698b5 100644 --- a/lib/table/otl/subtables/chaining/build.c +++ b/lib/table/otl/subtables/chaining/build.c @@ -1,6 +1,31 @@ #include "../chaining.h" #include "common.h" +bool otfcc_chainingLookupIsContextualLookup(const otl_Lookup *lookup) { + if (!(lookup->type == otl_type_gpos_chaining || lookup->type == otl_type_gsub_chaining)) + return false; + bool isContextual = true; + for (tableid_t j = 0; j < lookup->subtables.length; j++) { + const subtable_chaining *subtable = &(lookup->subtables.items[j]->chaining); + if (subtable->type == otl_chaining_classified) { + for (tableid_t k = 0; k < subtable->rulesCount; k++) { + otl_ChainingRule *rule = subtable->rules[k]; + tableid_t nBacktrack = rule->inputBegins; + tableid_t nLookahead = rule->matchCount - rule->inputEnds; + isContextual = isContextual && !nBacktrack && !nLookahead; + } + } else { + otl_ChainingRule *rule = (otl_ChainingRule *)&(subtable->rule); + tableid_t nBacktrack = rule->inputBegins; + tableid_t nLookahead = rule->matchCount - rule->inputEnds; + isContextual = isContextual && !nBacktrack && !nLookahead; + } + } + return isContextual; +} + +////// CHAINING + caryll_Buffer *otfcc_build_chaining_coverage(const otl_Subtable *_subtable) { const subtable_chaining *subtable = &(_subtable->chaining); otl_ChainingRule *rule = (otl_ChainingRule *)&(subtable->rule); @@ -43,13 +68,14 @@ caryll_Buffer *otfcc_build_chaining_classes(const otl_Subtable *_subtable) { coverage->numGlyphs = subtable->ic->numGlyphs; coverage->glyphs = subtable->ic->glyphs; - bk_Block *root = bk_new_Block(b16, 2, // format - p16, bk_newBlockFromBuffer(Coverage.build(coverage)), // coverage - p16, bk_newBlockFromBuffer(ClassDef.build(subtable->bc)), // BacktrackClassDef - p16, bk_newBlockFromBuffer(ClassDef.build(subtable->ic)), // InputClassDef - p16, bk_newBlockFromBuffer(ClassDef.build(subtable->fc)), // LookaheadClassDef - b16, subtable->ic->maxclass + 1, // ChainSubClassSetCnt - bkover); + bk_Block *root = + bk_new_Block(b16, 2, // format + p16, bk_newBlockFromBuffer(Coverage.build(coverage)), // coverage + p16, bk_newBlockFromBuffer(ClassDef.build(subtable->bc)), // BacktrackClassDef + p16, bk_newBlockFromBuffer(ClassDef.build(subtable->ic)), // InputClassDef + p16, bk_newBlockFromBuffer(ClassDef.build(subtable->fc)), // LookaheadClassDef + b16, subtable->ic->maxclass + 1, // ChainSubClassSetCnt + bkover); glyphclass_t *rcpg; NEW(rcpg, subtable->ic->maxclass + 1); @@ -114,3 +140,100 @@ caryll_Buffer *otfcc_build_chaining(const otl_Subtable *_subtable) { return otfcc_build_chaining_coverage(_subtable); } } + +////// CONTEXTUAL + +caryll_Buffer *otfcc_build_contextual_coverage(const otl_Subtable *_subtable) { + const subtable_chaining *subtable = &(_subtable->chaining); + otl_ChainingRule *rule = (otl_ChainingRule *)&(subtable->rule); + tableid_t nInput = rule->inputEnds - rule->inputBegins; + tableid_t nSubst = rule->applyCount; + reverseBacktracks(rule); + + bk_Block *root = bk_new_Block(b16, 3, // format + bkover); + + bk_push(root, b16, nInput, bkover); + bk_push(root, b16, nSubst, bkover); + for (tableid_t j = rule->inputBegins; j < rule->inputEnds; j++) { + bk_push(root, p16, bk_newBlockFromBuffer(Coverage.build(rule->match[j])), bkover); + } + for (tableid_t j = 0; j < nSubst; j++) { + bk_push(root, b16, rule->apply[j].index, // position + b16, rule->apply[j].lookup.index, // lookup + bkover); + } + + return bk_build_Block(root); +} + +caryll_Buffer *otfcc_build_contextual_classes(const otl_Subtable *_subtable) { + const subtable_chaining *subtable = &(_subtable->chaining); + + otl_Coverage *coverage; + NEW(coverage); + coverage->numGlyphs = subtable->ic->numGlyphs; + coverage->glyphs = subtable->ic->glyphs; + + bk_Block *root = + bk_new_Block(b16, 2, // format + p16, bk_newBlockFromBuffer(Coverage.build(coverage)), // coverage + p16, bk_newBlockFromBuffer(ClassDef.build(subtable->ic)), // InputClassDef + b16, subtable->ic->maxclass + 1, // ChainSubClassSetCnt + bkover); + + glyphclass_t *rcpg; + NEW(rcpg, subtable->ic->maxclass + 1); + for (glyphclass_t j = 0; j <= subtable->ic->maxclass; j++) { + rcpg[j] = 0; + } + for (tableid_t j = 0; j < subtable->rulesCount; j++) { + tableid_t ib = subtable->rules[j]->inputBegins; + tableid_t startClass = subtable->rules[j]->match[ib]->glyphs[0].index; + if (startClass <= subtable->ic->maxclass) rcpg[startClass] += 1; + } + + for (glyphclass_t j = 0; j <= subtable->ic->maxclass; j++) { + if (rcpg[j]) { + bk_Block *cset = bk_new_Block(b16, rcpg[j], // ChainSubClassRuleCnt + bkover); + for (tableid_t k = 0; k < subtable->rulesCount; k++) { + otl_ChainingRule *rule = subtable->rules[k]; + glyphclass_t startClass = rule->match[rule->inputBegins]->glyphs[0].index; + if (startClass != j) { continue; } + reverseBacktracks(rule); + tableid_t nInput = rule->inputEnds - rule->inputBegins; + tableid_t nSubst = rule->applyCount; + bk_Block *r = bk_new_Block(bkover); + + bk_push(r, b16, nInput, bkover); + bk_push(r, b16, nSubst, bkover); + for (tableid_t m = rule->inputBegins + 1; m < rule->inputEnds; m++) { + bk_push(r, b16, rule->match[m]->glyphs[0].index, bkover); + } + + for (tableid_t m = 0; m < nSubst; m++) { + bk_push(r, b16, rule->apply[m].index, // position + b16, rule->apply[m].lookup.index, // lookup index + bkover); + } + bk_push(cset, p16, r, bkover); + } + bk_push(root, p16, cset, bkover); + } else { + bk_push(root, p16, NULL, bkover); + } + } + + FREE(coverage); + FREE(rcpg); + return bk_build_Block(root); +} + +caryll_Buffer *otfcc_build_contextual(const otl_Subtable *_subtable) { + if (_subtable->chaining.type == otl_chaining_classified) { + return otfcc_build_contextual_classes(_subtable); + } else { + return otfcc_build_contextual_coverage(_subtable); + } +} diff --git a/lib/table/otl/subtables/chaining/classifier.c b/lib/table/otl/subtables/chaining/classifier.c index aa80a4b5..bbde273c 100644 --- a/lib/table/otl/subtables/chaining/classifier.c +++ b/lib/table/otl/subtables/chaining/classifier.c @@ -121,7 +121,8 @@ static otl_ClassDef *toClass(classifier_hash **h) { } return cd; } -tableid_t tryClassifyAround(const otl_Lookup *lookup, tableid_t j, OUT subtable_chaining **classifiedST) { +tableid_t tryClassifyAround(const otl_Lookup *lookup, tableid_t j, + OUT subtable_chaining **classifiedST) { tableid_t compatibleCount = 0; classifier_hash *hb = NULL; classifier_hash *hi = NULL; @@ -214,8 +215,10 @@ FAIL:; return 0; } } -tableid_t otfcc_classifiedBuildChaining(const otl_Lookup *lookup, OUT caryll_Buffer ***subtableBuffers, +tableid_t otfcc_classifiedBuildChaining(const otl_Lookup *lookup, + OUT caryll_Buffer ***subtableBuffers, MODIFY size_t *lastOffset) { + bool isContextual = otfcc_chainingLookupIsContextualLookup(lookup); tableid_t subtablesWritten = 0; NEW(*subtableBuffers, lookup->subtables.length); for (tableid_t j = 0; j < lookup->subtables.length; j++) { @@ -224,7 +227,8 @@ tableid_t otfcc_classifiedBuildChaining(const otl_Lookup *lookup, OUT caryll_Buf subtable_chaining *st = st0; // Try to classify subtables after j into j j += tryClassifyAround(lookup, j, &st); - caryll_Buffer *buf = otfcc_build_chaining((otl_Subtable *)st); + caryll_Buffer *buf = isContextual ? otfcc_build_contextual((otl_Subtable *)st) + : otfcc_build_chaining((otl_Subtable *)st); if (st != st0) { iSubtable_chaining.free(st); } (*subtableBuffers)[subtablesWritten] = buf; *lastOffset += buf->size; diff --git a/premake5.lua b/premake5.lua index 6f636bc8..997fd797 100644 --- a/premake5.lua +++ b/premake5.lua @@ -3,7 +3,7 @@ require "dep/premake-modules/ninja" MAIN_VER = '0' SECONDARY_VER = '10' -PATCH_VER = '3' +PATCH_VER = '4' function cbuildoptions() -- Windows diff --git a/src/otfccdump.c b/src/otfccdump.c index 30910007..69606296 100644 --- a/src/otfccdump.c +++ b/src/otfccdump.c @@ -79,6 +79,7 @@ int main(int argc, char *argv[]) { {"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}}; otfcc_Options *options = otfcc_newOptions(); @@ -125,6 +126,8 @@ int main(int argc, char *argv[]) { 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': @@ -150,6 +153,9 @@ int main(int argc, char *argv[]) { break; } } + + if (options->debug_wait_on_start) { getchar(); } + options->logger->setVerbosity(options->logger, options->quiet ? 0 : options->verbose ? 0xFF : 1);