From bfa02aa198f967662f58113e16ea6dd9dc9ebcb2 Mon Sep 17 00:00:00 2001 From: belleve Date: Thu, 3 May 2018 14:54:45 +0800 Subject: [PATCH 01/16] Log a warning about SCALED_COMPONENT_OFFSET --- lib/table/glyf.h | 4 +++- lib/table/glyf/build.c | 1 + lib/table/glyf/read.c | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) 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..056295a3 100644 --- a/lib/table/glyf/read.c +++ b/lib/table/glyf/read.c @@ -186,6 +186,10 @@ static glyf_Glyph *otfcc_read_composite_glyph(font_file_pointer start, } 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); From dc8667a7a7ee264062c1f25832a9f8fe1f560228 Mon Sep 17 00:00:00 2001 From: belleve Date: Wed, 9 May 2018 14:23:09 +0800 Subject: [PATCH 02/16] otfcc: now it would try to build contextual lookups if the lookup is simple enough --- lib/table/otl/build.c | 18 ++- lib/table/otl/subtables/chaining.h | 3 + lib/table/otl/subtables/chaining/build.c | 139 +++++++++++++++++- lib/table/otl/subtables/chaining/classifier.c | 10 +- 4 files changed, 153 insertions(+), 17 deletions(-) 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..315fac13 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,102 @@ 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 nBacktrack = rule->inputBegins; + tableid_t nInput = rule->inputEnds - rule->inputBegins; + tableid_t nLookahead = rule->matchCount - rule->inputEnds; + 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 - nBacktrack, // 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; From 3132a92ffd2493d032b3ceaf113cc6f5fa5c9740 Mon Sep 17 00:00:00 2001 From: belleve Date: Tue, 15 May 2018 16:02:03 +0800 Subject: [PATCH 03/16] revert the order when DFSing BKBlocks --- lib/bk/bkgraph.c | 3 +-- lib/table/otl/subtables/chaining/build.c | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) 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/table/otl/subtables/chaining/build.c b/lib/table/otl/subtables/chaining/build.c index 315fac13..ffe698b5 100644 --- a/lib/table/otl/subtables/chaining/build.c +++ b/lib/table/otl/subtables/chaining/build.c @@ -146,9 +146,7 @@ caryll_Buffer *otfcc_build_chaining(const otl_Subtable *_subtable) { 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 nBacktrack = rule->inputBegins; tableid_t nInput = rule->inputEnds - rule->inputBegins; - tableid_t nLookahead = rule->matchCount - rule->inputEnds; tableid_t nSubst = rule->applyCount; reverseBacktracks(rule); @@ -161,8 +159,8 @@ caryll_Buffer *otfcc_build_contextual_coverage(const otl_Subtable *_subtable) { 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 - nBacktrack, // position - b16, rule->apply[j].lookup.index, // lookup + bk_push(root, b16, rule->apply[j].index, // position + b16, rule->apply[j].lookup.index, // lookup bkover); } From 8ac3eb4a8217950798576b016b36006fd7e6f2b2 Mon Sep 17 00:00:00 2001 From: belleve Date: Fri, 25 May 2018 15:46:48 +0800 Subject: [PATCH 04/16] cmap: prioritize format 12 subtables. --- lib/table/cmap.c | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/lib/table/cmap.c b/lib/table/cmap.c index e2cf5757..2fc96ae6 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); From 59906461e7a981ee4a96702e18cdfbf072482c86 Mon Sep 17 00:00:00 2001 From: belleve Date: Tue, 11 Dec 2018 16:28:24 +0800 Subject: [PATCH 05/16] fix #56 --- lib/table/glyf/read.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/table/glyf/read.c b/lib/table/glyf/read.c index 056295a3..8976dde7 100644 --- a/lib/table/glyf/read.c +++ b/lib/table/glyf/read.c @@ -181,7 +181,7 @@ 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; From 53d82c5344142e1e8e74c8dcff92d592844e3d03 Mon Sep 17 00:00:00 2001 From: belleve Date: Tue, 11 Dec 2018 16:31:25 +0800 Subject: [PATCH 06/16] correct appveyor config --- appveyor.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index f413778d..66785652 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,6 +4,8 @@ environment: platform: - x64 +image: Previous Visual Studio 2017 + configuration: - Release From 6d94c301ca4fcb7bffbe1ddc7c211bf3c58a182c Mon Sep 17 00:00:00 2001 From: mrhso Date: Fri, 28 Dec 2018 13:08:26 +0800 Subject: [PATCH 07/16] AppVeyor: VS 2017 --- appveyor.yml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 66785652..dd70ad73 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,10 +1,10 @@ environment: - VS_VERSION: vs2015 + VS_VERSION: vs2017 platform: - x64 -image: Previous Visual Studio 2017 +image: Visual Studio 2017 configuration: - Release @@ -12,10 +12,7 @@ configuration: 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 From 000c1a9684bf29b79c7bcf4bab470a4d60bfab69 Mon Sep 17 00:00:00 2001 From: belleve Date: Wed, 2 Jan 2019 20:23:39 +0800 Subject: [PATCH 08/16] Add boundary check in raw file reading. Fixes #60. --- include/otfcc/options.h | 1 + lib/font/caryll-sfnt.c | 3 ++- lib/support/bin-io.h | 19 ++++++++++++++++--- src/otfccdump.c | 6 ++++++ 4 files changed, 25 insertions(+), 4 deletions(-) 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/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/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/src/otfccdump.c b/src/otfccdump.c index 0e2deed1..60f8f4cd 100644 --- a/src/otfccdump.c +++ b/src/otfccdump.c @@ -80,6 +80,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(); @@ -126,6 +127,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': @@ -151,6 +154,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); From ad01e3608293a548bedf87704f35e4c0529804d3 Mon Sep 17 00:00:00 2001 From: belleve Date: Wed, 2 Jan 2019 20:59:56 +0800 Subject: [PATCH 09/16] Better handling corrupted CFF charstrings. Fix #59. --- lib/libcff/cff-parser.c | 6 ++++++ lib/support/unicodeconv/unicodeconv.c | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) 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/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) { From bafdded90b06d871c4a29adbcda35273afc3ccd1 Mon Sep 17 00:00:00 2001 From: Cyano Hao Date: Tue, 29 Jan 2019 12:20:29 +0800 Subject: [PATCH 10/16] add support for 'OS/2' table version 0 --- lib/table/OS_2.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/table/OS_2.c b/lib/table/OS_2.c index bc5d0744..490441f8 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 + if (length < 78) 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); @@ -50,6 +50,10 @@ table_OS_2 *otfcc_readOS_2(const otfcc_Packet packet, const otfcc_Options *optio 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); } From 47f4b38ada2e57af0c794974bda9be49780d65c8 Mon Sep 17 00:00:00 2001 From: Cyano Hao Date: Tue, 29 Jan 2019 12:42:24 +0800 Subject: [PATCH 11/16] add support for 'OS/2' table defined in Apple's TrueType Reference Manual --- lib/table/OS_2.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/table/OS_2.c b/lib/table/OS_2.c index 490441f8..91f35acc 100644 --- a/lib/table/OS_2.c +++ b/lib/table/OS_2.c @@ -18,8 +18,8 @@ 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 0 - if (length < 78) goto OS_2_CORRUPTED; + // 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); @@ -45,6 +45,9 @@ 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); From 8058d0a9e3f68d47a9422da32c68f866ffc63dd5 Mon Sep 17 00:00:00 2001 From: myd7349 Date: Thu, 27 Jun 2019 18:12:31 +0800 Subject: [PATCH 12/16] Fix base64 encoding length calculation --- lib/support/base64/base64.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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; From 4c4f7993024068bcab672471cc7563e3998d3ad4 Mon Sep 17 00:00:00 2001 From: Belleve Invis Date: Sun, 28 Jul 2019 11:50:19 -0700 Subject: [PATCH 13/16] Fix output corruption in CFF::fontMatrix --- lib/table/CFF.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 From 9e9428bd175fe6d6836f0459c681d05dc1ef88a3 Mon Sep 17 00:00:00 2001 From: "Ryan A. Pavlik" Date: Tue, 19 Nov 2019 15:13:05 -0600 Subject: [PATCH 14/16] Update README.md Fix Ninja build instructions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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. From 76a21eacabb9da1c05ecbc800e7fbeee48e06334 Mon Sep 17 00:00:00 2001 From: Cyano Hao Date: Mon, 23 Dec 2019 00:03:18 +0800 Subject: [PATCH 15/16] drop cmap format 4 subtable if length > 65535 (use format 12 instead and build a dummy one) --- lib/table/cmap.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/lib/table/cmap.c b/lib/table/cmap.c index 2fc96ae6..164ba757 100644 --- a/lib/table/cmap.c +++ b/lib/table/cmap.c @@ -548,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); @@ -715,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 @@ -756,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 @@ -773,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 From 65aa1079f614bea3db3dc798aaedb6295c9b5a9e Mon Sep 17 00:00:00 2001 From: Cyano Hao Date: Sun, 12 Apr 2020 09:30:12 +0800 Subject: [PATCH 16/16] bump version --- premake5.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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