Fix for incorrect font coordinate scaling

This commit is contained in:
Chlumsky 2024-03-21 18:56:27 +01:00
parent 6d252a7dc3
commit bc9f02e156
3 changed files with 143 additions and 62 deletions

View File

@ -12,7 +12,6 @@
namespace msdfgen { namespace msdfgen {
#define F26DOT6_TO_DOUBLE(x) (1/64.*double(x))
#define F16DOT16_TO_DOUBLE(x) (1/65536.*double(x)) #define F16DOT16_TO_DOUBLE(x) (1/65536.*double(x))
#define DOUBLE_TO_F16DOT16(x) FT_Fixed(65536.*x) #define DOUBLE_TO_F16DOT16(x) FT_Fixed(65536.*x)
@ -35,14 +34,14 @@ class FontHandle {
friend FontHandle *loadFont(FreetypeHandle *library, const char *filename); friend FontHandle *loadFont(FreetypeHandle *library, const char *filename);
friend FontHandle *loadFontData(FreetypeHandle *library, const byte *data, int length); friend FontHandle *loadFontData(FreetypeHandle *library, const byte *data, int length);
friend void destroyFont(FontHandle *font); friend void destroyFont(FontHandle *font);
friend bool getFontMetrics(FontMetrics &metrics, FontHandle *font); friend bool getFontMetrics(FontMetrics &metrics, FontHandle *font, FontCoordinateScaling coordinateScaling);
friend bool getFontWhitespaceWidth(double &spaceAdvance, double &tabAdvance, FontHandle *font); friend bool getFontWhitespaceWidth(double &spaceAdvance, double &tabAdvance, FontHandle *font, FontCoordinateScaling coordinateScaling);
friend bool getGlyphCount(unsigned &output, FontHandle *font); friend bool getGlyphCount(unsigned &output, FontHandle *font);
friend bool getGlyphIndex(GlyphIndex &glyphIndex, FontHandle *font, unicode_t unicode); friend bool getGlyphIndex(GlyphIndex &glyphIndex, FontHandle *font, unicode_t unicode);
friend bool loadGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, double *advance); friend bool loadGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, FontCoordinateScaling coordinateScaling, double *outAdvance);
friend bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, double *advance); friend bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, FontCoordinateScaling coordinateScaling, double *outAdvance);
friend bool getKerning(double &output, FontHandle *font, GlyphIndex glyphIndex0, GlyphIndex glyphIndex1); friend bool getKerning(double &output, FontHandle *font, GlyphIndex glyphIndex0, GlyphIndex glyphIndex1, FontCoordinateScaling coordinateScaling);
friend bool getKerning(double &output, FontHandle *font, unicode_t unicode0, unicode_t unicode1); friend bool getKerning(double &output, FontHandle *font, unicode_t unicode0, unicode_t unicode1, FontCoordinateScaling coordinateScaling);
#ifndef MSDFGEN_DISABLE_VARIABLE_FONTS #ifndef MSDFGEN_DISABLE_VARIABLE_FONTS
friend bool setFontVariationAxis(FreetypeHandle *library, FontHandle *font, const char *name, double coordinate); friend bool setFontVariationAxis(FreetypeHandle *library, FontHandle *font, const char *name, double coordinate);
friend bool listFontVariationAxes(std::vector<FontVariationAxis> &axes, FreetypeHandle *library, FontHandle *font); friend bool listFontVariationAxes(std::vector<FontVariationAxis> &axes, FreetypeHandle *library, FontHandle *font);
@ -54,26 +53,27 @@ class FontHandle {
}; };
struct FtContext { struct FtContext {
double scale;
Point2 position; Point2 position;
Shape *shape; Shape *shape;
Contour *contour; Contour *contour;
}; };
static Point2 ftPoint2(const FT_Vector &vector) { static Point2 ftPoint2(const FT_Vector &vector, double scale) {
return Point2(F26DOT6_TO_DOUBLE(vector.x), F26DOT6_TO_DOUBLE(vector.y)); return Point2(scale*vector.x, scale*vector.y);
} }
static int ftMoveTo(const FT_Vector *to, void *user) { static int ftMoveTo(const FT_Vector *to, void *user) {
FtContext *context = reinterpret_cast<FtContext *>(user); FtContext *context = reinterpret_cast<FtContext *>(user);
if (!(context->contour && context->contour->edges.empty())) if (!(context->contour && context->contour->edges.empty()))
context->contour = &context->shape->addContour(); context->contour = &context->shape->addContour();
context->position = ftPoint2(*to); context->position = ftPoint2(*to, context->scale);
return 0; return 0;
} }
static int ftLineTo(const FT_Vector *to, void *user) { static int ftLineTo(const FT_Vector *to, void *user) {
FtContext *context = reinterpret_cast<FtContext *>(user); FtContext *context = reinterpret_cast<FtContext *>(user);
Point2 endpoint = ftPoint2(*to); Point2 endpoint = ftPoint2(*to, context->scale);
if (endpoint != context->position) { if (endpoint != context->position) {
context->contour->addEdge(EdgeHolder(context->position, endpoint)); context->contour->addEdge(EdgeHolder(context->position, endpoint));
context->position = endpoint; context->position = endpoint;
@ -83,9 +83,9 @@ static int ftLineTo(const FT_Vector *to, void *user) {
static int ftConicTo(const FT_Vector *control, const FT_Vector *to, void *user) { static int ftConicTo(const FT_Vector *control, const FT_Vector *to, void *user) {
FtContext *context = reinterpret_cast<FtContext *>(user); FtContext *context = reinterpret_cast<FtContext *>(user);
Point2 endpoint = ftPoint2(*to); Point2 endpoint = ftPoint2(*to, context->scale);
if (endpoint != context->position) { if (endpoint != context->position) {
context->contour->addEdge(EdgeHolder(context->position, ftPoint2(*control), endpoint)); context->contour->addEdge(EdgeHolder(context->position, ftPoint2(*control, context->scale), endpoint));
context->position = endpoint; context->position = endpoint;
} }
return 0; return 0;
@ -93,14 +93,26 @@ static int ftConicTo(const FT_Vector *control, const FT_Vector *to, void *user)
static int ftCubicTo(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) { static int ftCubicTo(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) {
FtContext *context = reinterpret_cast<FtContext *>(user); FtContext *context = reinterpret_cast<FtContext *>(user);
Point2 endpoint = ftPoint2(*to); Point2 endpoint = ftPoint2(*to, context->scale);
if (endpoint != context->position || crossProduct(ftPoint2(*control1)-endpoint, ftPoint2(*control2)-endpoint)) { if (endpoint != context->position || crossProduct(ftPoint2(*control1, context->scale)-endpoint, ftPoint2(*control2, context->scale)-endpoint)) {
context->contour->addEdge(EdgeHolder(context->position, ftPoint2(*control1), ftPoint2(*control2), endpoint)); context->contour->addEdge(EdgeHolder(context->position, ftPoint2(*control1, context->scale), ftPoint2(*control2, context->scale), endpoint));
context->position = endpoint; context->position = endpoint;
} }
return 0; return 0;
} }
static double getFontCoordinateScale(const FT_Face &face, FontCoordinateScaling coordinateScaling) {
switch (coordinateScaling) {
case FontCoordinateScaling::LEGACY:
return MSDFGEN_LEGACY_FONT_COORDINATE_SCALE;
case FontCoordinateScaling::KEEP_INTEGERS:
return 1;
case FontCoordinateScaling::EM_NORMALIZED:
return 1./(face->units_per_EM ? face->units_per_EM : 1);
}
return 1;
}
GlyphIndex::GlyphIndex(unsigned index) : index(index) { } GlyphIndex::GlyphIndex(unsigned index) : index(index) { }
unsigned GlyphIndex::getIndex() const { unsigned GlyphIndex::getIndex() const {
@ -129,10 +141,11 @@ FontHandle *adoptFreetypeFont(FT_Face ftFace) {
return handle; return handle;
} }
FT_Error readFreetypeOutline(Shape &output, FT_Outline *outline) { FT_Error readFreetypeOutline(Shape &output, FT_Outline *outline, double scale) {
output.contours.clear(); output.contours.clear();
output.inverseYAxis = false; output.inverseYAxis = false;
FtContext context = { }; FtContext context = { };
context.scale = scale;
context.shape = &output; context.shape = &output;
FT_Outline_Funcs ftFunctions; FT_Outline_Funcs ftFunctions;
ftFunctions.move_to = &ftMoveTo; ftFunctions.move_to = &ftMoveTo;
@ -179,25 +192,27 @@ void destroyFont(FontHandle *font) {
delete font; delete font;
} }
bool getFontMetrics(FontMetrics &metrics, FontHandle *font) { bool getFontMetrics(FontMetrics &metrics, FontHandle *font, FontCoordinateScaling coordinateScaling) {
metrics.emSize = F26DOT6_TO_DOUBLE(font->face->units_per_EM); double scale = getFontCoordinateScale(font->face, coordinateScaling);
metrics.ascenderY = F26DOT6_TO_DOUBLE(font->face->ascender); metrics.emSize = scale*font->face->units_per_EM;
metrics.descenderY = F26DOT6_TO_DOUBLE(font->face->descender); metrics.ascenderY = scale*font->face->ascender;
metrics.lineHeight = F26DOT6_TO_DOUBLE(font->face->height); metrics.descenderY = scale*font->face->descender;
metrics.underlineY = F26DOT6_TO_DOUBLE(font->face->underline_position); metrics.lineHeight = scale*font->face->height;
metrics.underlineThickness = F26DOT6_TO_DOUBLE(font->face->underline_thickness); metrics.underlineY = scale*font->face->underline_position;
metrics.underlineThickness = scale*font->face->underline_thickness;
return true; return true;
} }
bool getFontWhitespaceWidth(double &spaceAdvance, double &tabAdvance, FontHandle *font) { bool getFontWhitespaceWidth(double &spaceAdvance, double &tabAdvance, FontHandle *font, FontCoordinateScaling coordinateScaling) {
double scale = getFontCoordinateScale(font->face, coordinateScaling);
FT_Error error = FT_Load_Char(font->face, ' ', FT_LOAD_NO_SCALE); FT_Error error = FT_Load_Char(font->face, ' ', FT_LOAD_NO_SCALE);
if (error) if (error)
return false; return false;
spaceAdvance = F26DOT6_TO_DOUBLE(font->face->glyph->advance.x); spaceAdvance = scale*font->face->glyph->advance.x;
error = FT_Load_Char(font->face, '\t', FT_LOAD_NO_SCALE); error = FT_Load_Char(font->face, '\t', FT_LOAD_NO_SCALE);
if (error) if (error)
return false; return false;
tabAdvance = F26DOT6_TO_DOUBLE(font->face->glyph->advance.x); tabAdvance = scale*font->face->glyph->advance.x;
return true; return true;
} }
@ -211,33 +226,42 @@ bool getGlyphIndex(GlyphIndex &glyphIndex, FontHandle *font, unicode_t unicode)
return glyphIndex.getIndex() != 0; return glyphIndex.getIndex() != 0;
} }
bool loadGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, double *advance) { bool loadGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, FontCoordinateScaling coordinateScaling, double *outAdvance) {
if (!font) if (!font)
return false; return false;
FT_Error error = FT_Load_Glyph(font->face, glyphIndex.getIndex(), FT_LOAD_NO_SCALE); FT_Error error = FT_Load_Glyph(font->face, glyphIndex.getIndex(), FT_LOAD_NO_SCALE);
if (error) if (error)
return false; return false;
if (advance) double scale = getFontCoordinateScale(font->face, coordinateScaling);
*advance = F26DOT6_TO_DOUBLE(font->face->glyph->advance.x); if (outAdvance)
return !readFreetypeOutline(output, &font->face->glyph->outline); *outAdvance = scale*font->face->glyph->advance.x;
return !readFreetypeOutline(output, &font->face->glyph->outline, scale);
} }
bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, double *advance) { bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, FontCoordinateScaling coordinateScaling, double *outAdvance) {
return loadGlyph(output, font, GlyphIndex(FT_Get_Char_Index(font->face, unicode)), advance); return loadGlyph(output, font, GlyphIndex(FT_Get_Char_Index(font->face, unicode)), coordinateScaling, outAdvance);
} }
bool getKerning(double &output, FontHandle *font, GlyphIndex glyphIndex0, GlyphIndex glyphIndex1) { bool loadGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, double *outAdvance) {
return loadGlyph(output, font, glyphIndex, FontCoordinateScaling::LEGACY, outAdvance);
}
bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, double *outAdvance) {
return loadGlyph(output, font, unicode, FontCoordinateScaling::LEGACY, outAdvance);
}
bool getKerning(double &output, FontHandle *font, GlyphIndex glyphIndex0, GlyphIndex glyphIndex1, FontCoordinateScaling coordinateScaling) {
FT_Vector kerning; FT_Vector kerning;
if (FT_Get_Kerning(font->face, glyphIndex0.getIndex(), glyphIndex1.getIndex(), FT_KERNING_UNSCALED, &kerning)) { if (FT_Get_Kerning(font->face, glyphIndex0.getIndex(), glyphIndex1.getIndex(), FT_KERNING_UNSCALED, &kerning)) {
output = 0; output = 0;
return false; return false;
} }
output = F26DOT6_TO_DOUBLE(kerning.x); output = getFontCoordinateScale(font->face, coordinateScaling)*kerning.x;
return true; return true;
} }
bool getKerning(double &output, FontHandle *font, unicode_t unicode0, unicode_t unicode1) { bool getKerning(double &output, FontHandle *font, unicode_t unicode0, unicode_t unicode1, FontCoordinateScaling coordinateScaling) {
return getKerning(output, font, GlyphIndex(FT_Get_Char_Index(font->face, unicode0)), GlyphIndex(FT_Get_Char_Index(font->face, unicode1))); return getKerning(output, font, GlyphIndex(FT_Get_Char_Index(font->face, unicode0)), GlyphIndex(FT_Get_Char_Index(font->face, unicode1)), coordinateScaling);
} }
#ifndef MSDFGEN_DISABLE_VARIABLE_FONTS #ifndef MSDFGEN_DISABLE_VARIABLE_FONTS

View File

@ -5,6 +5,8 @@
namespace msdfgen { namespace msdfgen {
#define MSDFGEN_LEGACY_FONT_COORDINATE_SCALE (1/64.)
typedef unsigned unicode_t; typedef unsigned unicode_t;
class FreetypeHandle; class FreetypeHandle;
@ -45,6 +47,16 @@ struct FontVariationAxis {
double defaultValue; double defaultValue;
}; };
/// The scaling applied to font glyph coordinates when loading a glyph
enum class FontCoordinateScaling {
/// The incorrect legacy version that was in effect before version 1.12, coordinate values are divided by 64
LEGACY,
/// The coordinates are kept as the integer values native to the font file
KEEP_INTEGERS,
/// The coordinates will be normalized to the em size, i.e. 1 = 1 em
EM_NORMALIZED
};
/// Initializes the FreeType library. /// Initializes the FreeType library.
FreetypeHandle *initializeFreetype(); FreetypeHandle *initializeFreetype();
/// Deinitializes the FreeType library. /// Deinitializes the FreeType library.
@ -54,7 +66,7 @@ void deinitializeFreetype(FreetypeHandle *library);
/// Creates a FontHandle from FT_Face that was loaded by the user. destroyFont must still be called but will not affect the FT_Face. /// Creates a FontHandle from FT_Face that was loaded by the user. destroyFont must still be called but will not affect the FT_Face.
FontHandle *adoptFreetypeFont(FT_Face ftFace); FontHandle *adoptFreetypeFont(FT_Face ftFace);
/// Converts the geometry of FreeType's FT_Outline to a Shape object. /// Converts the geometry of FreeType's FT_Outline to a Shape object.
FT_Error readFreetypeOutline(Shape &output, FT_Outline *outline); FT_Error readFreetypeOutline(Shape &output, FT_Outline *outline, double scale = MSDFGEN_LEGACY_FONT_COORDINATE_SCALE);
#endif #endif
/// Loads a font file and returns its handle. /// Loads a font file and returns its handle.
@ -64,19 +76,22 @@ FontHandle *loadFontData(FreetypeHandle *library, const byte *data, int length);
/// Unloads a font. /// Unloads a font.
void destroyFont(FontHandle *font); void destroyFont(FontHandle *font);
/// Outputs the metrics of a font. /// Outputs the metrics of a font.
bool getFontMetrics(FontMetrics &metrics, FontHandle *font); bool getFontMetrics(FontMetrics &metrics, FontHandle *font, FontCoordinateScaling coordinateScaling = FontCoordinateScaling::LEGACY);
/// Outputs the width of the space and tab characters. /// Outputs the width of the space and tab characters.
bool getFontWhitespaceWidth(double &spaceAdvance, double &tabAdvance, FontHandle *font); bool getFontWhitespaceWidth(double &spaceAdvance, double &tabAdvance, FontHandle *font, FontCoordinateScaling coordinateScaling = FontCoordinateScaling::LEGACY);
/// Outputs the total number of glyphs available in the font. /// Outputs the total number of glyphs available in the font.
bool getGlyphCount(unsigned &output, FontHandle *font); bool getGlyphCount(unsigned &output, FontHandle *font);
/// Outputs the glyph index corresponding to the specified Unicode character. /// Outputs the glyph index corresponding to the specified Unicode character.
bool getGlyphIndex(GlyphIndex &glyphIndex, FontHandle *font, unicode_t unicode); bool getGlyphIndex(GlyphIndex &glyphIndex, FontHandle *font, unicode_t unicode);
/// Loads the geometry of a glyph from a font. /// Loads the geometry of a glyph from a font.
bool loadGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, double *advance = NULL); bool loadGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, FontCoordinateScaling coordinateScaling, double *outAdvance = NULL);
bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, double *advance = NULL); bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, FontCoordinateScaling coordinateScaling, double *outAdvance = NULL);
// Legacy API - FontCoordinateScaling is LEGACY
bool loadGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, double *outAdvance = NULL);
bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, double *outAdvance = NULL);
/// Outputs the kerning distance adjustment between two specific glyphs. /// Outputs the kerning distance adjustment between two specific glyphs.
bool getKerning(double &output, FontHandle *font, GlyphIndex glyphIndex0, GlyphIndex glyphIndex1); bool getKerning(double &output, FontHandle *font, GlyphIndex glyphIndex0, GlyphIndex glyphIndex1, FontCoordinateScaling coordinateScaling = FontCoordinateScaling::LEGACY);
bool getKerning(double &output, FontHandle *font, unicode_t unicode0, unicode_t unicode1); bool getKerning(double &output, FontHandle *font, unicode_t unicode0, unicode_t unicode1, FontCoordinateScaling coordinateScaling = FontCoordinateScaling::LEGACY);
#ifndef MSDFGEN_DISABLE_VARIABLE_FONTS #ifndef MSDFGEN_DISABLE_VARIABLE_FONTS
/// Sets a single variation axis of a variable font. /// Sets a single variation axis of a variable font.

View File

@ -402,6 +402,10 @@ static const char *const helpText =
"\tSets the dimensions of the output image.\n" "\tSets the dimensions of the output image.\n"
" -edgecolors <sequence>\n" " -edgecolors <sequence>\n"
"\tOverrides automatic edge coloring with the specified color sequence.\n" "\tOverrides automatic edge coloring with the specified color sequence.\n"
#ifdef MSDFGEN_EXTENSIONS
" -emnormalize\n"
"\tBefore applying scale, normalizes font glyph coordinates so that 1 = 1 em.\n"
#endif
" -errorcorrection <mode>\n" " -errorcorrection <mode>\n"
"\tChanges the MSDF/MTSDF error correction mode. Use -errorcorrection help for a list of valid modes.\n" "\tChanges the MSDF/MTSDF error correction mode. Use -errorcorrection help for a list of valid modes.\n"
" -errordeviationratio <ratio>\n" " -errordeviationratio <ratio>\n"
@ -426,6 +430,10 @@ static const char *const helpText =
"\tDisplays this help.\n" "\tDisplays this help.\n"
" -legacy\n" " -legacy\n"
"\tUses the original (legacy) distance field algorithms.\n" "\tUses the original (legacy) distance field algorithms.\n"
#ifdef MSDFGEN_EXTENSIONS
" -noemnormalize\n"
"\tRaw integer font glyph coordinates will be used. Without this option, legacy scaling will be applied.\n"
#endif
#ifdef MSDFGEN_USE_SKIA #ifdef MSDFGEN_USE_SKIA
" -nopreprocess\n" " -nopreprocess\n"
"\tDisables path preprocessing which resolves self-intersections and overlapping contours.\n" "\tDisables path preprocessing which resolves self-intersections and overlapping contours.\n"
@ -547,6 +555,8 @@ int main(int argc, const char *const *argv) {
bool glyphIndexSpecified = false; bool glyphIndexSpecified = false;
GlyphIndex glyphIndex; GlyphIndex glyphIndex;
unicode_t unicode = 0; unicode_t unicode = 0;
FontCoordinateScaling fontCoordinateScaling = FontCoordinateScaling::LEGACY;
bool fontCoordinateScalingSpecified = false;
#endif #endif
int width = 64, height = 64; int width = 64, height = 64;
@ -631,6 +641,21 @@ int main(int argc, const char *const *argv) {
} }
continue; continue;
} }
ARG_CASE("-noemnormalize", 0) {
fontCoordinateScaling = FontCoordinateScaling::KEEP_INTEGERS;
fontCoordinateScalingSpecified = true;
continue;
}
ARG_CASE("-emnormalize", 0) {
fontCoordinateScaling = FontCoordinateScaling::EM_NORMALIZED;
fontCoordinateScalingSpecified = true;
continue;
}
ARG_CASE("-legacyfontscaling", 0) {
fontCoordinateScaling = FontCoordinateScaling::LEGACY;
fontCoordinateScalingSpecified = true;
continue;
}
#else #else
ARG_CASE("-svg", 1) { ARG_CASE("-svg", 1) {
ABORT("SVG input is not available in core-only version."); ABORT("SVG input is not available in core-only version.");
@ -668,6 +693,10 @@ int main(int argc, const char *const *argv) {
} }
ARG_CASE("-legacy", 0) { ARG_CASE("-legacy", 0) {
legacyMode = true; legacyMode = true;
#ifdef MSDFGEN_EXTENSIONS
fontCoordinateScaling = FontCoordinateScaling::LEGACY;
fontCoordinateScalingSpecified = true;
#endif
continue; continue;
} }
ARG_CASE("-nopreprocess", 0) { ARG_CASE("-nopreprocess", 0) {
@ -987,28 +1016,40 @@ int main(int argc, const char *const *argv) {
case FONT: case VAR_FONT: { case FONT: case VAR_FONT: {
if (!glyphIndexSpecified && !unicode) if (!glyphIndexSpecified && !unicode)
ABORT("No character specified! Use -font <file.ttf/otf> <character code>. Character code can be a Unicode index (65, 0x41), a character in apostrophes ('A'), or a glyph index prefixed by g (g36, g0x24)."); ABORT("No character specified! Use -font <file.ttf/otf> <character code>. Character code can be a Unicode index (65, 0x41), a character in apostrophes ('A'), or a glyph index prefixed by g (g36, g0x24).");
FreetypeHandle *ft = initializeFreetype(); struct FreetypeFontGuard {
if (!ft) FreetypeHandle *ft;
return -1; FontHandle *font;
FontHandle *font = ( FreetypeFontGuard() : ft(), font() { }
~FreetypeFontGuard() {
if (ft) {
if (font)
destroyFont(font);
deinitializeFreetype(ft);
}
}
} guard;
if (!(guard.ft = initializeFreetype()))
ABORT("Failed to initialize FreeType library.");
if (!(guard.font = (
#ifndef MSDFGEN_DISABLE_VARIABLE_FONTS #ifndef MSDFGEN_DISABLE_VARIABLE_FONTS
inputType == VAR_FONT ? loadVarFont(ft, input) : inputType == VAR_FONT ? loadVarFont(guard.ft, input) :
#endif #endif
loadFont(ft, input) loadFont(guard.ft, input)
); )))
if (!font) {
deinitializeFreetype(ft);
ABORT("Failed to load font file."); ABORT("Failed to load font file.");
}
if (unicode) if (unicode)
getGlyphIndex(glyphIndex, font, unicode); getGlyphIndex(glyphIndex, guard.font, unicode);
if (!loadGlyph(shape, font, glyphIndex, &glyphAdvance)) { if (!loadGlyph(shape, guard.font, glyphIndex, fontCoordinateScaling, &glyphAdvance))
destroyFont(font);
deinitializeFreetype(ft);
ABORT("Failed to load glyph from font file."); ABORT("Failed to load glyph from font file.");
if (!fontCoordinateScalingSpecified && (!autoFrame || scaleSpecified || rangeMode == RANGE_UNIT || mode == METRICS || printMetrics || shapeExport)) {
fputs(
"Warning: Using legacy font coordinate conversion for compatibility reasons.\n"
" The scaling behavior in this configuration will likely change in a future version resulting in different output.\n"
" To silence this warning, use one of the following options:\n"
" -noemnormalize to switch to the correct native font coordinates,\n"
" -emnormalize to switch to coordinates normalized to 1 em, or\n"
" -legacyfontscaling to keep current behavior and make sure it will not change.\n", stderr);
} }
destroyFont(font);
deinitializeFreetype(ft);
break; break;
} }
#endif #endif
@ -1026,9 +1067,10 @@ int main(int argc, const char *const *argv) {
FILE *file = fopen(input, "r"); FILE *file = fopen(input, "r");
if (!file) if (!file)
ABORT("Failed to load shape description file."); ABORT("Failed to load shape description file.");
if (!readShapeDescription(file, shape, &skipColoring)) bool readSuccessful = readShapeDescription(file, shape, &skipColoring);
ABORT("Parse error in shape description.");
fclose(file); fclose(file);
if (!readSuccessful)
ABORT("Parse error in shape description.");
break; break;
} }
default:; default:;