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