From 6e1815047689b85b57da2bf81798e6cdcc89b4a4 Mon Sep 17 00:00:00 2001 From: Zachary Scheuren Date: Sun, 5 Jul 2020 14:24:41 -0700 Subject: [PATCH 1/8] Add [STAT] to STAT table messages Update STAT handling to write version 1.2 table only if there are Format 4 Axis value tables Warn if unregistered axis tags are not uppercase Warn if Format 2 default value is not in min-max range Fail if DesignAxis tag has already been defined Fail if Axis Value Table of the same format has already been defined with the same values Add `[name]` to name table messages Warn when overwriting existing nameid Fail if GSUB or STAT are defined before name table and name table sets nameids above 255: https://github.com/adobe-type-tools/afdko/issues/1178 Docs: Clarify use of Unicode values in column 3 of GlyphOrderAndAliasDB https://github.com/adobe-type-tools/afdko/issues/1177 --- .../makeotf_lib/build/hotpccts/featgram.g | 38 ++- c/makeotf/makeotf_lib/source/hotconv/STAT.c | 123 ++++++- .../makeotf_lib/source/hotconv/featgram.c | 28 +- c/makeotf/makeotf_lib/source/hotconv/name.c | 23 +- docs/MakeOTFUserGuide.md | 21 +- docs/OpenTypeFeatureFileSpecification.md | 310 ++++++++++++------ .../expected_output/fealib/bug1178.ttx | 109 ++++++ .../expected_output/spec/9i-2.ttx | 2 +- .../expected_output/spec/9i-20.ttx | 2 +- .../expected_output/spec/9i-21.ttx | 2 +- .../expected_output/spec/9i-22.ttx | 2 +- .../expected_output/spec/9i-25.ttx | 2 +- .../expected_output/spec/9i-4.ttx | 2 +- .../expected_output/spec/9i-5.ttx | 2 +- .../expected_output/spec/9i-6.ttx | 2 +- .../makeotfexe_data/input/fealib/bug1178.fea | 31 ++ .../fealib/incomplete_glyph_range.bad.fea | 2 + .../input/fealib/name_after_STAT.bad.fea | 26 ++ tests/makeotfexe_data/input/spec/9i-21.fea | 8 +- tests/makeotfexe_test.py | 23 +- 20 files changed, 623 insertions(+), 135 deletions(-) create mode 100644 tests/makeotfexe_data/expected_output/fealib/bug1178.ttx create mode 100644 tests/makeotfexe_data/input/fealib/bug1178.fea create mode 100644 tests/makeotfexe_data/input/fealib/incomplete_glyph_range.bad.fea create mode 100644 tests/makeotfexe_data/input/fealib/name_after_STAT.bad.fea diff --git a/c/makeotf/makeotf_lib/build/hotpccts/featgram.g b/c/makeotf/makeotf_lib/build/hotpccts/featgram.g index a272ed9e4..4e0ee0306 100644 --- a/c/makeotf/makeotf_lib/build/hotpccts/featgram.g +++ b/c/makeotf/makeotf_lib/build/hotpccts/featgram.g @@ -46,6 +46,9 @@ void featureFile(void); featCtx h; /* Not reentrant; see featNew() comments */ hotCtx g; +int sawSTAT = FALSE; +int sawFeatNames = FALSE; +int sawCVParams = FALSE; >> /* ----------------------------- Tokens ------------------------------------ */ @@ -363,16 +366,16 @@ glyphClass[int named, char *gcname]>[GNode *gnode] gid = featMapGName2GID(g, firstPart, FALSE ); endgid = featMapGName2GID(g, secondPart, FALSE ); if (gid != 0 && endgid != 0) { - gcAddRange(gid, endgid, firstPart, secondPart); + gcAddRange(gid, endgid, firstPart, secondPart); } else { - hotMsg(g, hotFATAL, "aborting because of errors"); + hotMsg(g, hotFATAL, "incomplete glyph range detected"); } } else { - featMapGName2GID(g, firstPart, FALSE); - hotMsg(g, hotFATAL, "aborting because of errors"); + featMapGName2GID(g, firstPart, FALSE); + hotMsg(g, hotFATAL, "incomplete glyph range or glyph not in font"); } zzEXIT(zztasp4); } @@ -1170,13 +1173,17 @@ featureNameEntry : << long plat, spec, lang; >> nameEntry>[plat, spec, lang] - << addFeatureNameString(plat, spec, lang);>> + << + sawFeatNames = TRUE; + addFeatureNameString(plat, spec, lang); + >> ; featureNames : << - h->featNameID = 0; + sawFeatNames = TRUE; + h->featNameID = nameReserveUserID(h->g); >> K_feat_names "\{" @@ -1193,13 +1200,14 @@ featureNames cvParameterBlock : << + sawCVParams = TRUE; h->cvParameters.FeatUILabelNameID = 0; h->cvParameters.FeatUITooltipTextNameID = 0; h->cvParameters.SampleTextNameID = 0; h->cvParameters.NumNamedParameters = 0; h->cvParameters.FirstParamUILabelNameID = 0; h->cvParameters.charValues.cnt = 0; - h->featNameID = 0; + h->featNameID = nameReserveUserID(h->g); >> K_cv_params "\{" @@ -2081,6 +2089,9 @@ elidedFallbackNameID table_STAT : t:K_STAT <> + << + sawSTAT = TRUE; + >> "\{" ( ( @@ -2219,8 +2230,17 @@ table_name >> numUInt16Ext>[id] - - + << + if (sawSTAT && id > 255) + hotMsg(g, hotFATAL, "name table should be defined before " + "STAT table with nameids above 255"); + if (sawCVParams && id > 255) + hotMsg(g, hotFATAL, "name table should be defined before " + "GSUB cvParameters with nameids above 255"); + if (sawFeatNames && id > 255) + hotMsg(g, hotFATAL, "name table should be defined before " + "GSUB featureNames with nameids above 255"); + >> { numUInt16Ext>[plat] << diff --git a/c/makeotf/makeotf_lib/source/hotconv/STAT.c b/c/makeotf/makeotf_lib/source/hotconv/STAT.c index 15b00aa4a..cf4415e1b 100644 --- a/c/makeotf/makeotf_lib/source/hotconv/STAT.c +++ b/c/makeotf/makeotf_lib/source/hotconv/STAT.c @@ -129,11 +129,11 @@ int STATFill(hotCtx g) { } if (!nameVerifyIDExists(g, h->elidedFallbackNameID)) - hotMsg(g, hotFATAL, "ElidedFallbackNameID points to a nameID that " + hotMsg(g, hotFATAL, "[STAT] ElidedFallbackNameID points to a nameID that " "does not exist in \"name\" table."); h->tbl.majorVersion = 1; - h->tbl.minorVersion = 2; + h->tbl.minorVersion = 1; h->tbl.designAxisSize = AXIS_RECORD_SIZE; h->tbl.designAxisCount = h->designAxes.cnt; h->tbl.designAxesOffset = NULL_OFFSET; @@ -160,18 +160,19 @@ int STATFill(hotCtx g) { if (!axisIndexOfTag(h, av->format1.axisTag, &av->format1.axisIndex)) { hotMsg(g, hotFATAL, - "No STAT DesignAxis defined for \"%c%c%c%c\".", + "[STAT] No DesignAxis defined for \"%c%c%c%c\".", TAG_ARG(av->format1.axisTag)); } break; case 4: + h->tbl.minorVersion = 2; for (j = 0; j < av->format4.axisCount; j++) { if (!axisIndexOfTag(h, av->format4.axisValues[j].axisTag, &av->format4.axisValues[j].axisIndex)) { hotMsg(g, hotFATAL, - "No STAT DesignAxis defined for \"%c%c%c%c\".", + "[STAT] No DesignAxis defined for \"%c%c%c%c\".", TAG_ARG(av->format4.axisValues[j].axisTag)); } } @@ -294,12 +295,45 @@ void STATFree(hotCtx g) { void STATAddDesignAxis(hotCtx g, Tag tag, uint16_t nameID, uint16_t ordering) { STATCtx h = g->ctx.STAT; AxisRecord *ar; - long i; + long index; + int i; + long j; + + // Currently registered tags are 'wght', 'wdth', 'opsz', 'ital', 'slnt' + char tagString[4] = {TAG_ARG(tag)}; + const uint32_t *regTags[5] = { + TAG('i','t','a','l'), TAG('o','p','s','z'), + TAG('s','l','n','t'), TAG('w','d','t','h'), + TAG('w','g','h','t'), + }; + + // Unregistered tags should be all uppercase + int regTag = false; + int size = sizeof(regTags) / sizeof(regTags[0]); + for (i = 0; i < size; i++) { + if (tag == regTags[i]) { + regTag = true; + break; + } + } + if (!regTag) { + int hasLC = false; + for (j = 0; j <= 4; j++) { + if (tagString[j] >= 'a' && tagString[j] <= 'z') { + hasLC = true; + break; + } + } + if (hasLC) { + hotMsg(g, hotWARNING, "[STAT] Unregistered axis tag \"%c%c%c%c\" " + "should be uppercase.\n", TAG_ARG(tag)); + } + } - for (i = 0; i < h->designAxes.cnt; i++) { - AxisRecord *ar = &h->designAxes.array[i]; + for (index = 0; index < h->designAxes.cnt; index++) { + AxisRecord *ar = &h->designAxes.array[index]; if (ar->axisTag == tag) - hotMsg(g, hotFATAL, "STAT DesignAxis with \"%c%c%c%c\" tag " + hotMsg(g, hotFATAL, "[STAT] DesignAxis tag \"%c%c%c%c\" " "is already defined.", TAG_ARG(tag)); } @@ -314,6 +348,7 @@ void STATAddAxisValueTable(hotCtx g, uint16_t format, Tag *axisTags, uint16_t nameID, Fixed minValue, Fixed maxValue) { STATCtx h = g->ctx.STAT; long i; + long j; AxisValueTable *av = dnaNEXT(h->axisValues); @@ -324,6 +359,14 @@ void STATAddAxisValueTable(hotCtx g, uint16_t format, Tag *axisTags, switch (format) { case 1: + for (i = 0; i < h->axisValues.cnt; i++) { + AxisValueTable *refav = &h->axisValues.array[i]; + if (refav->format1.axisTag == axisTags[0] + && refav->format1.value == values[0]) + hotMsg(g, hotFATAL, "[STAT] AxisValueTable already defined " + "for axis \"%c%c%c%c\" with value %.2f\n", + TAG_ARG(axisTags[0]), FIX2DBL(values[0])); + } av->size = AXIS_VALUE_TABLE1_SIZE; av->format1.axisTag = axisTags[0]; av->format1.flags = flags; @@ -332,6 +375,25 @@ void STATAddAxisValueTable(hotCtx g, uint16_t format, Tag *axisTags, break; case 2: + if ((values[0] < minValue) || (values[0] > maxValue)) { + hotMsg(g, hotWARNING, "[STAT] \"%c%c%c%c\" AxisValue " + "default value %.2f is not in range %.2f-%.2f", + TAG_ARG(axisTags[0]), FIX2DBL(values[0]), + FIX2DBL(minValue), FIX2DBL(maxValue)); + } + + for (i = 0; i < h->axisValues.cnt; i++) { + AxisValueTable *refav = &h->axisValues.array[i]; + if (refav->format2.axisTag == axisTags[0] + && refav->format2.nominalValue == values[0] + && refav->format2.rangeMinValue == minValue + && refav->format2.rangeMaxValue == maxValue) + hotMsg(g, hotFATAL, "[STAT] AxisValueTable already defined " + "for axis \"%c%c%c%c\" with values %.2f %.2f %.2f\n", + TAG_ARG(axisTags[0]), FIX2DBL(values[0]), + FIX2DBL(minValue), FIX2DBL(maxValue)); + } + av->size = AXIS_VALUE_TABLE2_SIZE; av->format2.axisTag = axisTags[0]; av->format2.flags = flags; @@ -342,6 +404,16 @@ void STATAddAxisValueTable(hotCtx g, uint16_t format, Tag *axisTags, break; case 3: + for (i = 0; i < h->axisValues.cnt; i++) { + AxisValueTable *refav = &h->axisValues.array[i]; + if (refav->format3.axisTag == axisTags[0] + && refav->format3.value == values[0] + && refav->format3.linkedValue == minValue) + hotMsg(g, hotFATAL, "[STAT] AxisValueTable already defined " + "for axis \"%c%c%c%c\" with values %.2f %.2f\n", + TAG_ARG(axisTags[0]), FIX2DBL(values[0]), + FIX2DBL(minValue)); + } av->size = AXIS_VALUE_TABLE3_SIZE; av->format3.axisTag = axisTags[0]; av->format3.flags = flags; @@ -351,6 +423,41 @@ void STATAddAxisValueTable(hotCtx g, uint16_t format, Tag *axisTags, break; case 4: + for (i = 0; i < h->axisValues.cnt; i++) { + AxisValueTable *refav = &h->axisValues.array[i]; + bool dupeAVT[count]; + bool isDupe = true; + if (refav->format4.axisCount == count) { + for (j = 0; j < count; j++) { + if (refav->format4.axisValues[j].axisTag == axisTags[j] + && refav->format4.axisValues[j].value == values[j]) { + dupeAVT[j] = true; + } + else { + dupeAVT[j] = false; + } + } + for (j = 0; j < count; j++) { + if (!dupeAVT[j]) { + isDupe = false; +// break; + } + } + if (isDupe) { + // message + number of axes * 14 (wght ddddd.dd) + char dupeMsg[54 + count * 14]; + dupeMsg[0] = '\0'; + sprintf(dupeMsg, "[STAT] AxisValueTable already defined with locations: "); + for (j = 0; j < count; j++) { + char axisMsg[20]; + axisMsg[0] = '\0'; + sprintf(axisMsg, "%c%c%c%c %.2f ", TAG_ARG(axisTags[j]), FIX2DBL(values[j])); + strcat(dupeMsg, axisMsg); + } + hotMsg(g, hotFATAL, dupeMsg); + } + } + } av->size = AXIS_VALUE_TABLE4_SIZE(count); av->format4.axisCount = count; av->format4.flags = flags; diff --git a/c/makeotf/makeotf_lib/source/hotconv/featgram.c b/c/makeotf/makeotf_lib/source/hotconv/featgram.c index 103b85151..0aeea10bf 100644 --- a/c/makeotf/makeotf_lib/source/hotconv/featgram.c +++ b/c/makeotf/makeotf_lib/source/hotconv/featgram.c @@ -61,6 +61,9 @@ void featureFile(void); featCtx h; /* Not reentrant; see featNew() comments */ hotCtx g; +int sawSTAT = FALSE; +int sawFeatNames = FALSE; +int sawCVParams = FALSE; GID #ifdef __USE_PROTOS @@ -177,12 +180,12 @@ char *gcname; if (gid != 0 && endgid != 0) { gcAddRange(gid, endgid, firstPart, secondPart); } else { - hotMsg(g, hotFATAL, "aborting because of errors"); + hotMsg(g, hotFATAL, "incomplete glyph range detected"); } } else { featMapGName2GID(g, firstPart, FALSE); - hotMsg(g, hotFATAL, "aborting because of errors"); + hotMsg(g, hotFATAL, "incomplete glyph range or glyph not in font"); } zzEXIT(zztasp4); } else { @@ -2344,6 +2347,8 @@ featureNameEntry() spec = _trv.spec; lang = _trv.lang; } + + sawFeatNames = TRUE; addFeatureNameString(plat, spec, lang); zzEXIT(zztasp1); return; @@ -2365,7 +2370,8 @@ featureNames() zzBLOCK(zztasp1); zzMake0; { - h->featNameID = 0; + sawFeatNames = TRUE; + h->featNameID = nameReserveUserID(h->g); zzmatch(K_feat_names); zzCONSUME; zzmatch(157); @@ -2414,13 +2420,14 @@ cvParameterBlock() zzBLOCK(zztasp1); zzMake0; { + sawCVParams = TRUE; h->cvParameters.FeatUILabelNameID = 0; h->cvParameters.FeatUITooltipTextNameID = 0; h->cvParameters.SampleTextNameID = 0; h->cvParameters.NumNamedParameters = 0; h->cvParameters.FirstParamUILabelNameID = 0; h->cvParameters.charValues.cnt = 0; - h->featNameID = 0; + h->featNameID = nameReserveUserID(h->g); zzmatch(K_cv_params); zzCONSUME; zzmatch(157); @@ -5056,6 +5063,7 @@ table_STAT() checkTag(t.ulval, tableTag, 1); zzCONSUME; + sawSTAT = TRUE; zzmatch(157); zzCONSUME; { @@ -5542,6 +5550,18 @@ table_name() id = numUInt16Ext(); + if (sawSTAT && id > 255) + hotMsg(g, hotFATAL, + "name table should be defined before " + "STAT table with nameids above 255"); + if (sawCVParams && id > 255) + hotMsg(g, hotFATAL, + "name table should be defined before " + "GSUB cvParameters with nameids above 255"); + if (sawFeatNames && id > 255) + hotMsg(g, hotFATAL, + "name table should be defined before " + "GSUB featureNames with nameids above 255"); { zzBLOCK(zztasp4); zzMake0; diff --git a/c/makeotf/makeotf_lib/source/hotconv/name.c b/c/makeotf/makeotf_lib/source/hotconv/name.c index 26555db02..0c848f197 100644 --- a/c/makeotf/makeotf_lib/source/hotconv/name.c +++ b/c/makeotf/makeotf_lib/source/hotconv/name.c @@ -437,7 +437,7 @@ static char *translate2MacDflt(nameCtx h, char *src) { if (uv) { char macChar = mapUV2MacRoman(uv); if (macChar == 0) { - hotMsg(h->g, hotFATAL, "Could not translate UTF8 glyph code into Mac Roman in name table name %s", begin); + hotMsg(h->g, hotFATAL, "[name] Could not translate UTF8 glyph code into Mac Roman in name table name %s", begin); } *dst++ = macChar; } @@ -477,7 +477,7 @@ static void fillNames(nameCtx h) { HOT_NAME_FAMILY); if (tempString == NULL) { - hotMsg(h->g, hotFATAL, "I can't find a Family name for this font !"); + hotMsg(h->g, hotFATAL, "[name] I can't find a Family name for this font !"); } addWinDfltName(h, HOT_NAME_FAMILY, strlen(tempString), tempString); } @@ -525,7 +525,7 @@ static void fillNames(nameCtx h) { rec->languageId, HOT_NAME_FAMILY, strlen(Family), Family); if (doWarning) { - hotMsg(h->g, hotWARNING, "The Font Menu Name DB entry for this font is missing an MS Platform Compatible Family Name entry to match the MS Platform Preferred Family Name for language ID %d. Using the Preferred Name only.", rec->languageId); + hotMsg(h->g, hotWARNING, "[name] The Font Menu Name DB entry for this font is missing an MS Platform Compatible Family Name entry to match the MS Platform Preferred Family Name for language ID %d. Using the Preferred Name only.", rec->languageId); } } @@ -681,7 +681,7 @@ static void fillNames(nameCtx h) { rec->languageId, HOT_NAME_FAMILY, strlen(Family), Family); if (doWarning && (!doV1Names)) { - hotMsg(h->g, hotWARNING, "The Font Menu Name DB entry for this font is missing a Mac Platform Compatible Family Name entry to match the Mac Platform Preferred Family Name for language ID %d. Using the Preferred Name only.", rec->languageId); + hotMsg(h->g, hotWARNING, "[name] The Font Menu Name DB entry for this font is missing a Mac Platform Compatible Family Name entry to match the Mac Platform Preferred Family Name for language ID %d. Using the Preferred Name only.", rec->languageId); } } index++; @@ -817,7 +817,7 @@ static void fillNames(nameCtx h) { } if (Subfamily == NULL) { - hotMsg(h->g, hotFATAL, "no Mac subfamily name specified"); + hotMsg(h->g, hotFATAL, "[name] no Mac subfamily name specified"); } else if (strcmp(Subfamily, "Regular") == 0) { addName(h, HOT_NAME_MAC_PLATFORM, @@ -873,7 +873,7 @@ static void fillNames(nameCtx h) { } if (Subfamily == NULL) { - hotMsg(h->g, hotFATAL, "no Mac subfamily name specified"); + hotMsg(h->g, hotFATAL, "[name] no Mac subfamily name specified"); } else if (strcmp(Subfamily, "Regular") == 0) { addName(h, HOT_NAME_MAC_PLATFORM, @@ -1119,6 +1119,12 @@ void nameAddReg(hotCtx g, unsigned short languageId, unsigned short nameId, char *str) { nameCtx h = g->ctx.name; + if (nameVerifyIDExists(g, nameId)) { + char *foundstr = getName(h, platformId, platspecId, languageId, nameId); + if (foundstr != NULL) { + hotMsg(h->g, hotWARNING, "[name] Overwriting existing nameid %d %s with %s", nameId, foundstr, str); + } + } addName(h, platformId, platspecId, languageId, nameId, strlen(str), str); } @@ -1134,6 +1140,11 @@ unsigned short nameAddUser(hotCtx g, char *str) { unsigned short nameReserveUserID(hotCtx g) { nameCtx h = g->ctx.name; unsigned short nameId = h->userNameId++; + if (nameVerifyIDExists(g, nameId) && nameId > 255) { + while (nameVerifyIDExists(g, nameId)) { + nameId++; + } + } return nameId; } diff --git a/docs/MakeOTFUserGuide.md b/docs/MakeOTFUserGuide.md index 33ad36d48..71e6beac1 100644 --- a/docs/MakeOTFUserGuide.md +++ b/docs/MakeOTFUserGuide.md @@ -236,7 +236,22 @@ Versions of MakeOTF prior to FDK 2.5 used a similar syntax in the FontMenuNameDB If the key `c=` is used, then MakeOTF will build the older style name table. If the keys `l=` or `m=` are present, it will build the newer style name table . If none of these are present, then there is no difference in how the name table is built. ## **GlyphOrderAndAliasDB** (GOADB) -The GOADB file is used to rename and to establish an order for the glyphs in a font. It is a simple text file with one line per glyph name. Each line contains at least two fields, and optionally three fields. The first field is the final glyph name to be used in the output font. The second field is the ‘friendly’ name used in the source font data. The third field is a Unicode value, specified in the form `uniXXXX` or `uXXXX`, where `XXXX` is a Unicode value (hexadecimal). One may specify more than one Unicode value for a glyph by giving a comma separated list of values, for example: `uni0020,uni00A0`. The `XXXX` hexadecimal values *must* be either numerals (0-9) or uppercase letters. Values containing lowercase letters will be ignored. The source font is not required to have any glyphs that are named in the `GlyphOrderAndAliasDB` file. +The GOADB file is used to rename and to establish an order for the glyphs in a font. +It is a simple text file with one line per glyph name. Each line contains at least two fields, +and optionally three fields. The first field is the final glyph name to be used in the output font. +The second field is the ‘friendly’ name used in the source font data. +The third field is a Unicode value, specified in the form `uniXXXX` or `uXXXX[XX]` (see [note](#unicode_note)). +One may specify more than one Unicode value for a glyph by giving a comma separated list of values, for example: `uni0020,uni00A0`. +The `XXXX` hexadecimal values *must* be either numerals (0-9) or uppercase letters. Values containing lowercase letters will be ignored. +The source font is not required to have any glyphs that are named in the `GlyphOrderAndAliasDB` file. + + +Note: Unicode values can be used in the form `uniXXXX` or `uXXXX[XX]` where `XXXX[XX]` is a hexadecimal Unicode value. +The number of `X` is determined by the codepoint. For example, `U+0903` can be written as either +`uni0903` or `u0903`. If the codepoint requires 5 or 6 digits, for example `U+F0002` or `U+F00041`, +then the format must contain the same number of digits: `uF0002` or `uF00041`. This only applies when +assigning Unicode values using column 3. + It should be noted that the ordering, renaming, and Unicode override operations are applied only if the `–r` option or the `-ga` option is specified. These operations work as follows: @@ -246,11 +261,11 @@ It should be noted that the ordering, renaming, and Unicode override operations 3) Override the default Unicode encoding by MakeOTF. MakeOTF will assign Unicode values to glyphs in a non-CID font when possible. (For a CID font, the Unicode values are provided by the Adobe CMap files.) The rules used are as follows: - a) If the third field of the GOADB record for a glyph contains a Unicode value in the form uniXXXX or uXXXX (where XXXX stands for a Unicode value), assign that Unicode value to the glyph. Else b); + a) If the third field of the GOADB record for a glyph contains a Unicode value in the form uniXXXX or uXXXX\[XX\] (see [note](#unicode_note)), assign that Unicode value to the glyph. Else b); b) If a glyph name is in the [Adobe Glyph List For New Fonts](https://github.com/adobe-type-tools/agl-aglfn/blob/master/aglfn.txt), use the assigned Unicode value. Else c); - c) If the glyph name is in the form uniXXXX or uXXXX (where XXXX stands for a Unicode value), assign the Unicode value. Else d); + c) If the glyph name is in the form uniXXXX or uXXXX\[XX\] (see [note](#unicode_note)), assign the Unicode value. Else d); d) Do not assign any Unicode value. diff --git a/docs/OpenTypeFeatureFileSpecification.md b/docs/OpenTypeFeatureFileSpecification.md index 2c37f0e36..bc26db2f0 100644 --- a/docs/OpenTypeFeatureFileSpecification.md +++ b/docs/OpenTypeFeatureFileSpecification.md @@ -10,8 +10,8 @@ Copyright 2015-2020 Adobe. All Rights Reserved. This software is licensed as OpenSource, under the Apache License, Version 2.0. This license is available at: http://opensource.org/licenses/Apache-2.0. -Document version 1.25.0 -Last updated 22 May 2020 +Document version 1.25.1 +Last updated 5 July 2020 **Caution: Portions of the syntax unimplemented by Adobe are subject to change.** @@ -3562,10 +3562,12 @@ ElidedFallbackNameID ; ``` #### Design axes -There can be one or more design axes specified in the `STAT` table. +All of the design axes defined in the `fvar` table must be present in the `STAT` +table as well, but the order is not required to be the same. The `STAT` table +may also contain additional design axes not defined in the `fvar`. ```fea -DesignAxis { +DesignAxis { name ;+ };+ ``` @@ -3596,7 +3598,7 @@ flag ElidableAxisValueName OlderSiblingFontAttribute; The `location` statement takes several formats: -##### location format A +##### location format A (used in Axis value table [Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-1) and [Format 4](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-4)) ```fea location ;+ ``` @@ -3605,29 +3607,55 @@ location ;+ axes in the table. `value` is a signed number and can be specified using decimal, hex and octal formats as well (see §[9.e](#9.e)). -There can be more than one `location` statement when this format is used (in -this case the axis value will be `STAT` format 4 `AxisValue`, and format 1 -otherwise). +With a single `location` statement the `AxisValue` will be format 1. +If there are more than one `location` statements the `AxisValue` will be +format 4. -##### location format B +##### location format B (used in Axis value table [Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-2)) ```fea location - ; ``` -Format for `axisTag` and the other values as above, and there must be space -before the `-` to distinguish it from possible minus sign for -``. +Format for `axisTag` and the other values as above, and there must be a space +before the `-` to distinguish it from a possible minus sign for +``. To specify an open ended range use `-32767` to mean +negative infinity and `32767.99998` to mean positive infinity. +For example, the following AxisValue definitions mean that "Regular" on the +`wght` axis is defined with a nominal value of 400 and a range covering all +possible values below 400 up to and including 649. "Bold" is defined with a +nominal value of 700 and a range covering all values from 650 and above. +```fea + AxisValue { + location wght 400 -32768 - 650; + name "Regular"; + AxisValue { + location wght 700 650 - 32767.99998; + name "Bold"; + }; +``` There can be only one `location` statement when this format is used (the axis value will be `STAT` format 2 `AxisValue`). -##### location format C +##### location format C (used in Axis value table [Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-3)) ```fea location ; ``` Format for `axisTag` and the other values as above. +In the following example the `linkedValue` is used to style-link "Regular" and "Bold". + +```fea + AxisValue { + location wght 400 700; + name "Regular"; + AxisValue { + location wght 700; + name "Bold"; + }; +``` + There can be only one `location` statement when this format is used (the axis value will be `STAT` format 3 `AxisValue`). @@ -3637,109 +3665,204 @@ single STAT table. See Example 2 for a fully defined STAT table. ```fea table STAT { - ElidedFallbackName { name "Regular"; }; + ElidedFallbackName { name "Regular"; }; - DesignAxis wght 0 { name "Weight"; }; - DesignAxis ital 1 { name "Italic"; }; + DesignAxis wght 0 { name "Weight"; }; + DesignAxis ital 1 { name "Italic"; }; - # format 1 - AxisValue { - location wght 400; - name "Regular"; - name 3 1 0x411 "\5B9A\671F\7684"; - flag ElidableAxisValueName; - }; + # format 1 + AxisValue { + location wght 400; + name "Regular"; + name 3 1 0x411 "\5B9A\671F\7684"; + flag ElidableAxisValueName; + }; - # format 2 - AxisValue { - location wght 400 300 - 500; - name "Regular"; - flag ElidableAxisValueName; - }; + # format 2 + AxisValue { + location wght 400 300 - 500; + name "Regular"; + flag ElidableAxisValueName; + }; - # format 3 - AxisValue { - location wght 400 700; - name "Regular"; - flag ElidableAxisValueName; - }; + # format 3 + AxisValue { + location wght 400 700; + name "Regular"; + flag ElidableAxisValueName; + }; - # format 3 - AxisValue { - location ital 0 1; - name "Regular"; - flag ElidableAxisValueName; - }; + # format 3 + AxisValue { + location ital 0 1; + name "Regular"; + flag ElidableAxisValueName; + }; - # format 4 - AxisValue { - location wght 500; - location ital 1; - name "MediumItalic"; - flag ElidableAxisValueName; - }; + # format 4 + AxisValue { + location wght 500; + location ital 1; + name "MediumItalic"; + flag ElidableAxisValueName; + }; } STAT; ``` #### Example 2: -This example shows a fully defined STAT table with two axes in format 2. +This example shows two fully defined STAT tables with three axes in format 2. +These link an Upright variable font and an Italic variable font with the `ital` +axis. +For Upright: ```fea table STAT { ElidedFallbackName { name "Regular"; }; - DesignAxis wght 0 { name "Weight"; }; - DesignAxis opsz 1 { name "Optical"; }; + DesignAxis opsz 0 { name "Optical Size"; }; + DesignAxis wght 1 { name "Weight"; }; + DesignAxis ital 2 { name "Italic"; }; - AxisValue { - location wght 200 200 - 250; - name "ExtraLight"; - }; + AxisValue { + location wght 200 200 - 250; + name "ExtraLight"; + }; - AxisValue { - location wght 300 250 - 350; - name "Light"; - }; + AxisValue { + location wght 300 250 - 350; + name "Light"; + }; - AxisValue { - location wght 400 350 - 450; - name "Regular"; - flag ElidableAxisValueName; - }; + AxisValue { + location wght 400 350 - 450; + name "Regular"; + flag ElidableAxisValueName; + }; - AxisValue { - location wght 600 550 - 650; - name "Semibold"; - }; + AxisValue { + location wght 500 450 - 550; + name "Medium"; + flag ElidableAxisValueName; + }; - AxisValue { - location wght 700 650 - 750; - name "Bold"; - }; + AxisValue { + location wght 600 550 - 650; + name "Semibold"; + }; - AxisValue { - location wght 900 800 - 900; - name "Black"; - }; + AxisValue { + location wght 700 650 - 750; + name "Bold"; + }; - AxisValue { - location - opsz 6 0 - 8; - name "Caption"; - }; + AxisValue { + location wght 800 750 - 850; + name "ExtraBold"; + }; + + AxisValue { + location wght 900 850 - 900; + name "Black"; + }; - AxisValue { - location - opsz 10 8 - 24; - name "Text"; - flag ElidableAxisValueName; - }; + AxisValue { + location opsz 6 5 - 8; + name "Caption"; + }; + + AxisValue { + location opsz 10 8 - 24; + name "Text"; + flag ElidableAxisValueName; + }; + + AxisValue { + location opsz 60 24 - 100; + name "Display"; + }; + + AxisValue { + location ital 0 1; + name "Roman"; + flag ElidableAxisValueName; + }; - AxisValue { - location - opsz 60 24 - 100; - name "Display"; - }; +} STAT; +``` + +For Italic: +```fea +table STAT { + + ElidedFallbackName { name "Italic"; }; + + DesignAxis opsz 0 { name "Optical Size"; }; + DesignAxis wght 1 { name "Weight"; }; + DesignAxis ital 2 { name "Italic"; }; + + AxisValue { + location wght 200 200 - 250; + name "ExtraLight"; + }; + + AxisValue { + location wght 300 250 - 350; + name "Light"; + }; + + AxisValue { + location wght 400 350 - 450; + name "Regular"; + flag ElidableAxisValueName; + }; + + AxisValue { + location wght 500 450 - 550; + name "Medium"; + flag ElidableAxisValueName; + }; + + AxisValue { + location wght 600 550 - 650; + name "Semibold"; + }; + + AxisValue { + location wght 700 650 - 750; + name "Bold"; + }; + + AxisValue { + location wght 800 750 - 850; + name "ExtraBold"; + }; + + AxisValue { + location wght 900 850 - 900; + name "Black"; + }; + + AxisValue { + location opsz 6 5 - 8; + name "Caption"; + }; + + AxisValue { + location opsz 10 8 - 24; + name "Text"; + flag ElidableAxisValueName; + }; + + AxisValue { + location opsz 60 24 - 100; + name "Display"; + }; + + AxisValue { + location ital 1 0; + name "Italic"; + flag ElidableAxisValueName; + }; } STAT; ``` @@ -3800,6 +3923,9 @@ along with the tag `sbit`. ## 11. Document revisions +**v1.25.1 [5 July 2020]:** +* Added information and examples to [STAT table](#9.e) + **v1.25.0 [22 May 2020]:** * Added syntax for STAT table as discussed in diff --git a/tests/makeotfexe_data/expected_output/fealib/bug1178.ttx b/tests/makeotfexe_data/expected_output/fealib/bug1178.ttx new file mode 100644 index 000000000..2ace84301 --- /dev/null +++ b/tests/makeotfexe_data/expected_output/fealib/bug1178.ttx @@ -0,0 +1,109 @@ + + + + + + Untitled1 + + + Regular + + + 1.000;UKWN;Untitled1 + + + Untitled1 + + + Version 1.000;hotconv 1.0.114;makeotfexe 2.5.65599 DEVELOPMENT + + + Untitled1 + + + © 2014 - 2020 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name ‘Source’. + + + Untitled1 + + + Regular + + + 1.000;UKWN;Untitled1 + + + Untitled1 + + + Version 1.000;hotconv 1.0.114;makeotfexe 2.5.65599 DEVELOPMENT + + + Untitled1 + + + Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + + + Adobe Systems Incorporated + + + A Designer + + + http://www.adobe.com/type + + + Roman + + + Italic + + + Regular + + + Weight + + + Light + + + Regular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/makeotfexe_data/expected_output/spec/9i-2.ttx b/tests/makeotfexe_data/expected_output/spec/9i-2.ttx index d2ca2fcf5..ef93fb5bd 100644 --- a/tests/makeotfexe_data/expected_output/spec/9i-2.ttx +++ b/tests/makeotfexe_data/expected_output/spec/9i-2.ttx @@ -2,7 +2,7 @@ - + diff --git a/tests/makeotfexe_data/expected_output/spec/9i-20.ttx b/tests/makeotfexe_data/expected_output/spec/9i-20.ttx index fc15174be..e608198c7 100644 --- a/tests/makeotfexe_data/expected_output/spec/9i-20.ttx +++ b/tests/makeotfexe_data/expected_output/spec/9i-20.ttx @@ -50,7 +50,7 @@ - + diff --git a/tests/makeotfexe_data/expected_output/spec/9i-21.ttx b/tests/makeotfexe_data/expected_output/spec/9i-21.ttx index fc15174be..e608198c7 100644 --- a/tests/makeotfexe_data/expected_output/spec/9i-21.ttx +++ b/tests/makeotfexe_data/expected_output/spec/9i-21.ttx @@ -50,7 +50,7 @@ - + diff --git a/tests/makeotfexe_data/expected_output/spec/9i-22.ttx b/tests/makeotfexe_data/expected_output/spec/9i-22.ttx index 945b2daf8..90f8ce935 100644 --- a/tests/makeotfexe_data/expected_output/spec/9i-22.ttx +++ b/tests/makeotfexe_data/expected_output/spec/9i-22.ttx @@ -2,7 +2,7 @@ - + diff --git a/tests/makeotfexe_data/expected_output/spec/9i-25.ttx b/tests/makeotfexe_data/expected_output/spec/9i-25.ttx index 629404981..3a628416c 100644 --- a/tests/makeotfexe_data/expected_output/spec/9i-25.ttx +++ b/tests/makeotfexe_data/expected_output/spec/9i-25.ttx @@ -2,7 +2,7 @@ - + diff --git a/tests/makeotfexe_data/expected_output/spec/9i-4.ttx b/tests/makeotfexe_data/expected_output/spec/9i-4.ttx index 9f34f6828..7d8e722b7 100644 --- a/tests/makeotfexe_data/expected_output/spec/9i-4.ttx +++ b/tests/makeotfexe_data/expected_output/spec/9i-4.ttx @@ -2,7 +2,7 @@ - + diff --git a/tests/makeotfexe_data/expected_output/spec/9i-5.ttx b/tests/makeotfexe_data/expected_output/spec/9i-5.ttx index b4feeca48..b960a2c8e 100644 --- a/tests/makeotfexe_data/expected_output/spec/9i-5.ttx +++ b/tests/makeotfexe_data/expected_output/spec/9i-5.ttx @@ -2,7 +2,7 @@ - + diff --git a/tests/makeotfexe_data/expected_output/spec/9i-6.ttx b/tests/makeotfexe_data/expected_output/spec/9i-6.ttx index 7b250da63..6bd7a5a11 100644 --- a/tests/makeotfexe_data/expected_output/spec/9i-6.ttx +++ b/tests/makeotfexe_data/expected_output/spec/9i-6.ttx @@ -2,7 +2,7 @@ - + diff --git a/tests/makeotfexe_data/input/fealib/bug1178.fea b/tests/makeotfexe_data/input/fealib/bug1178.fea new file mode 100644 index 000000000..c01c1490e --- /dev/null +++ b/tests/makeotfexe_data/input/fealib/bug1178.fea @@ -0,0 +1,31 @@ +# https://github.com/adobe-type-tools/afdko/issues/1178 + +table name { + nameid 0 "\00a9 2014 - 2020 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name \2018Source\2019."; + nameid 7 "Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries."; + nameid 8 "Adobe Systems Incorporated"; + nameid 9 "A Designer"; + nameid 11 "http://www.adobe.com/type"; + nameid 256 "Roman"; + nameid 257 "Italic"; +} name; + + +table STAT { + + ElidedFallbackName { name "Regular"; }; + + DesignAxis wght 0 { name "Weight"; }; + + AxisValue { + location wght 300 250 - 350; + name "Light"; + }; + + AxisValue { + location wght 400 350 - 450; + name "Regular"; + flag ElidableAxisValueName; + }; + +} STAT; diff --git a/tests/makeotfexe_data/input/fealib/incomplete_glyph_range.bad.fea b/tests/makeotfexe_data/input/fealib/incomplete_glyph_range.bad.fea new file mode 100644 index 000000000..9db9ece22 --- /dev/null +++ b/tests/makeotfexe_data/input/fealib/incomplete_glyph_range.bad.fea @@ -0,0 +1,2 @@ + +@incomplete_range = [a- ]; diff --git a/tests/makeotfexe_data/input/fealib/name_after_STAT.bad.fea b/tests/makeotfexe_data/input/fealib/name_after_STAT.bad.fea new file mode 100644 index 000000000..45e5edd81 --- /dev/null +++ b/tests/makeotfexe_data/input/fealib/name_after_STAT.bad.fea @@ -0,0 +1,26 @@ +# name table should be defined before STAT to avoid possibly overwriting names + +table STAT { + ElidedFallbackName { name "Regular"; }; + + DesignAxis wght 0 { name "Weight"; }; + DesignAxis ital 1 { name "Italic"; }; + + AxisValue { + location wght 400.0 -300.54 - 450.6; + name "Regular"; + flag ElidableAxisValueName; + }; + + AxisValue { + location ital 1; + name "Italic"; + flag ElidableAxisValueName; + }; +} STAT; + + +table name { + nameid 256 "Roman"; + nameid 257 "Italic"; +} name; diff --git a/tests/makeotfexe_data/input/spec/9i-21.fea b/tests/makeotfexe_data/input/spec/9i-21.fea index 3bdfa5cec..a30ea329a 100644 --- a/tests/makeotfexe_data/input/spec/9i-21.fea +++ b/tests/makeotfexe_data/input/spec/9i-21.fea @@ -1,5 +1,9 @@ # TABLES: name,STAT +table name { + nameid 300 "Regular"; +} name; + table STAT { ElidedFallbackNameID 300; @@ -11,7 +15,3 @@ table STAT { flag ElidableAxisValueName; }; } STAT; - -table name { - nameid 300 "Regular"; -} name; diff --git a/tests/makeotfexe_test.py b/tests/makeotfexe_test.py index 4807502d7..ea3695461 100644 --- a/tests/makeotfexe_test.py +++ b/tests/makeotfexe_test.py @@ -553,6 +553,24 @@ def test_parameter_offset_overflow_bug1017(): assert differ([expected_txt, actual_txt]) +def test_bug1178(): + input_filename = 'fealib/font.pfa' + feat_filename = 'fealib/bug1178.fea' + ttx_filename = 'fealib/bug1178.ttx' + actual_path = get_temp_file_path() + runner(CMD + ['-o', 'f', f'_{get_input_path(input_filename)}', + 'ff', f'_{get_input_path(feat_filename)}', + 'o', f'_{actual_path}']) + actual_ttx = generate_ttx_dump(actual_path, ['name', 'STAT']) + expected_ttx = get_expected_path(ttx_filename) + assert differ([expected_ttx, actual_ttx, + '-s', + 'size = AXIS_VALUE_TABLE4_SIZE(count); av->format4.axisCount = count; From aad01f1d763fd5f170084da228d0bc662b6a8cc8 Mon Sep 17 00:00:00 2001 From: Zachary Scheuren Date: Sun, 5 Jul 2020 16:03:36 -0700 Subject: [PATCH 3/8] Fix whitespace reported by circleci --- c/makeotf/makeotf_lib/source/hotconv/STAT.c | 63 ++++++++++----------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/c/makeotf/makeotf_lib/source/hotconv/STAT.c b/c/makeotf/makeotf_lib/source/hotconv/STAT.c index f3f4b3215..3884d7cb3 100644 --- a/c/makeotf/makeotf_lib/source/hotconv/STAT.c +++ b/c/makeotf/makeotf_lib/source/hotconv/STAT.c @@ -425,38 +425,37 @@ void STATAddAxisValueTable(hotCtx g, uint16_t format, Tag *axisTags, case 4: for (i = 0; i < h->axisValues.cnt; i++) { AxisValueTable *refav = &h->axisValues.array[i]; - bool dupeAVT[99]; - bool isDupe = true; - if (refav->format4.axisCount == count) { - for (j = 0; j < count; j++) { - if (refav->format4.axisValues[j].axisTag == axisTags[j] - && refav->format4.axisValues[j].value == values[j]) { - dupeAVT[j] = true; - } - else { - dupeAVT[j] = false; - } - } - for (j = 0; j < count; j++) { - if (!dupeAVT[j]) { - isDupe = false; - break; - } - } - if (isDupe) { - // message + number of axes * 14 (wght ddddd.dd) - char dupeMsg[2048]; - dupeMsg[0] = '\0'; - sprintf(dupeMsg, "[STAT] AxisValueTable already defined with locations: "); - for (j = 0; j < count; j++) { - char axisMsg[20]; - axisMsg[0] = '\0'; - sprintf(axisMsg, "%c%c%c%c %.2f ", TAG_ARG(axisTags[j]), FIX2DBL(values[j])); - strcat(dupeMsg, axisMsg); - } - hotMsg(g, hotFATAL, dupeMsg); - } - } + bool dupeAVT[99]; + bool isDupe = true; + if (refav->format4.axisCount == count) { + for (j = 0; j < count; j++) { + if (refav->format4.axisValues[j].axisTag == axisTags[j] + && refav->format4.axisValues[j].value == values[j]) { + dupeAVT[j] = true; + } else { + dupeAVT[j] = false; + } + } + for (j = 0; j < count; j++) { + if (!dupeAVT[j]) { + isDupe = false; + break; + } + } + if (isDupe) { + // message + number of axes * 14 (wght ddddd.dd) + char dupeMsg[2048]; + dupeMsg[0] = '\0'; + sprintf(dupeMsg, "[STAT] AxisValueTable already defined with locations: "); + for (j = 0; j < count; j++) { + char axisMsg[20]; + axisMsg[0] = '\0'; + sprintf(axisMsg, "%c%c%c%c %.2f ", TAG_ARG(axisTags[j]), FIX2DBL(values[j])); + strcat(dupeMsg, axisMsg); + } + hotMsg(g, hotFATAL, dupeMsg); + } + } } av->size = AXIS_VALUE_TABLE4_SIZE(count); av->format4.axisCount = count; From 24f012ed910126be944b7376690ed7582e0dc1af Mon Sep 17 00:00:00 2001 From: Zachary Scheuren Date: Sun, 5 Jul 2020 16:53:20 -0700 Subject: [PATCH 4/8] Fix whitespace (again) reported by circleci --- c/makeotf/makeotf_lib/source/hotconv/STAT.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/c/makeotf/makeotf_lib/source/hotconv/STAT.c b/c/makeotf/makeotf_lib/source/hotconv/STAT.c index 3884d7cb3..1bc4ceb28 100644 --- a/c/makeotf/makeotf_lib/source/hotconv/STAT.c +++ b/c/makeotf/makeotf_lib/source/hotconv/STAT.c @@ -302,9 +302,9 @@ void STATAddDesignAxis(hotCtx g, Tag tag, uint16_t nameID, uint16_t ordering) { // Currently registered tags are 'wght', 'wdth', 'opsz', 'ital', 'slnt' char tagString[4] = {TAG_ARG(tag)}; const uint32_t *regTags[5] = { - TAG('i','t','a','l'), TAG('o','p','s','z'), - TAG('s','l','n','t'), TAG('w','d','t','h'), - TAG('w','g','h','t'), + TAG('i','t','a','l'), TAG('o','p','s','z'), + TAG('s','l','n','t'), TAG('w','d','t','h'), + TAG('w','g','h','t'), }; // Unregistered tags should be all uppercase From 9ec8646eded33cfe025bf5654965320eeb5c19ab Mon Sep 17 00:00:00 2001 From: Zachary Scheuren Date: Sun, 5 Jul 2020 17:22:58 -0700 Subject: [PATCH 5/8] Fix whitespace after comma --- c/makeotf/makeotf_lib/source/hotconv/STAT.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/c/makeotf/makeotf_lib/source/hotconv/STAT.c b/c/makeotf/makeotf_lib/source/hotconv/STAT.c index 1bc4ceb28..0d09d4d02 100644 --- a/c/makeotf/makeotf_lib/source/hotconv/STAT.c +++ b/c/makeotf/makeotf_lib/source/hotconv/STAT.c @@ -302,9 +302,11 @@ void STATAddDesignAxis(hotCtx g, Tag tag, uint16_t nameID, uint16_t ordering) { // Currently registered tags are 'wght', 'wdth', 'opsz', 'ital', 'slnt' char tagString[4] = {TAG_ARG(tag)}; const uint32_t *regTags[5] = { - TAG('i','t','a','l'), TAG('o','p','s','z'), - TAG('s','l','n','t'), TAG('w','d','t','h'), - TAG('w','g','h','t'), + TAG('i', 't', 'a', 'l'), + TAG('o', 'p', 's', 'z'), + TAG('s', 'l', 'n', 't'), + TAG('w', 'd', 't', 'h'), + TAG('w', 'g', 'h', 't'), }; // Unregistered tags should be all uppercase From eecdde8f262003fdb42f81caee7eee7c25ec6752 Mon Sep 17 00:00:00 2001 From: Zachary Scheuren Date: Wed, 8 Jul 2020 16:45:59 -0700 Subject: [PATCH 6/8] Fix buffer overflow --- c/makeotf/makeotf_lib/source/hotconv/STAT.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/makeotf/makeotf_lib/source/hotconv/STAT.c b/c/makeotf/makeotf_lib/source/hotconv/STAT.c index 0d09d4d02..0f3c8cba7 100644 --- a/c/makeotf/makeotf_lib/source/hotconv/STAT.c +++ b/c/makeotf/makeotf_lib/source/hotconv/STAT.c @@ -320,7 +320,7 @@ void STATAddDesignAxis(hotCtx g, Tag tag, uint16_t nameID, uint16_t ordering) { } if (!regTag) { int hasLC = false; - for (j = 0; j <= 4; j++) { + for (j = 0; j < 4; j++) { if (tagString[j] >= 'a' && tagString[j] <= 'z') { hasLC = true; break; From fe18d905296e2a7640f228f0c77e32e53642578c Mon Sep 17 00:00:00 2001 From: Zachary Scheuren Date: Wed, 8 Jul 2020 17:17:22 -0700 Subject: [PATCH 7/8] Update versions for makeotf, makeotfexe, hotconv --- c/makeotf/makeotf_lib/api/hotconv.h | 2 +- c/makeotf/source/main.c | 2 +- python/afdko/makeotf.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/c/makeotf/makeotf_lib/api/hotconv.h b/c/makeotf/makeotf_lib/api/hotconv.h index 45c2230d0..a30049c15 100644 --- a/c/makeotf/makeotf_lib/api/hotconv.h +++ b/c/makeotf/makeotf_lib/api/hotconv.h @@ -12,7 +12,7 @@ This software is licensed as OpenSource, under the Apache License, Version 2.0. extern "C" { #endif -#define HOT_VERSION 0x010072 /* Library version (1.0.114) */ +#define HOT_VERSION 0x010073 /* Library version (1.0.115) */ /* Major, minor, build = (HOT_VERSION >> 16) & 0xff, (HOT_VERSION >> 8) & 0xff, HOT_VERSION & 0xff) */ /* Warning: this string is now part of heuristic used by CoolType to identify the first round of CoolType fonts which had the backtrack sequence of a chaining diff --git a/c/makeotf/source/main.c b/c/makeotf/source/main.c index 69dcfa8e4..758c4888f 100644 --- a/c/makeotf/source/main.c +++ b/c/makeotf/source/main.c @@ -30,7 +30,7 @@ jmp_buf mark; -#define MAKEOTF_VERSION "2.5.65599" +#define MAKEOTF_VERSION "2.5.65600" /* Warning: this string is now part of heuristic used by CoolType to identify the first round of CoolType fonts which had the backtrack sequence of a chaining contextual substitution ordered incorrectly. Fonts with the old ordering MUST match diff --git a/python/afdko/makeotf.py b/python/afdko/makeotf.py index df446cb1e..48467cd87 100644 --- a/python/afdko/makeotf.py +++ b/python/afdko/makeotf.py @@ -26,7 +26,7 @@ """ __version__ = """\ -makeotf.py v2.8.0 June 21 2020 +makeotf.py v2.8.1 July 8 2020 """ __methods__ = """ From 9730e68fff0b1182ba2eb6e2ec9a9a1dee4d1d45 Mon Sep 17 00:00:00 2001 From: Zachary Scheuren Date: Wed, 8 Jul 2020 17:55:32 -0700 Subject: [PATCH 8/8] Fix failing test --- tests/makeotfexe_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/makeotfexe_test.py b/tests/makeotfexe_test.py index ea3695461..932f3db36 100644 --- a/tests/makeotfexe_test.py +++ b/tests/makeotfexe_test.py @@ -568,7 +568,8 @@ def test_bug1178(): '