Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

makeotfexe STAT/name table fixes #1179

Merged
merged 8 commits into from
Jul 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion c/makeotf/makeotf_lib/api/hotconv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
38 changes: 29 additions & 9 deletions c/makeotf/makeotf_lib/build/hotpccts/featgram.g
Original file line number Diff line number Diff line change
Expand Up @@ -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 ------------------------------------ */
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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
"\{"
Expand All @@ -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
"\{"
Expand Down Expand Up @@ -2081,6 +2089,9 @@ elidedFallbackNameID

table_STAT
: t:K_STAT <<checkTag($t.ulval, tableTag, 1);>>
<<
sawSTAT = TRUE;
>>
"\{"
(
(
Expand Down Expand Up @@ -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]
<<
Expand Down
124 changes: 116 additions & 8 deletions c/makeotf/makeotf_lib/source/hotconv/STAT.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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));
}
}
Expand Down Expand Up @@ -294,12 +295,47 @@ 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));
}

Expand All @@ -314,6 +350,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);

Expand All @@ -324,6 +361,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;
Expand All @@ -332,6 +377,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;
Expand All @@ -342,6 +406,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;
Expand All @@ -351,6 +425,40 @@ 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[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;
av->format4.flags = flags;
Expand Down
28 changes: 24 additions & 4 deletions c/makeotf/makeotf_lib/source/hotconv/featgram.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -2344,6 +2347,8 @@ featureNameEntry()
spec = _trv.spec;
lang = _trv.lang;
}

sawFeatNames = TRUE;
addFeatureNameString(plat, spec, lang);
zzEXIT(zztasp1);
return;
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -5056,6 +5063,7 @@ table_STAT()
checkTag(t.ulval, tableTag, 1);
zzCONSUME;

sawSTAT = TRUE;
zzmatch(157);
zzCONSUME;
{
Expand Down Expand Up @@ -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;
Expand Down
Loading