import-font.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. #include "import-font.h"
  2. #include <cstdlib>
  3. #include <queue>
  4. #include <ft2build.h>
  5. #include FT_FREETYPE_H
  6. #include FT_OUTLINE_H
  7. namespace msdfgen {
  8. #define REQUIRE(cond) { if (!(cond)) return false; }
  9. #define F26DOT6_TO_DOUBLE(x) (1/64.*double(x))
  10. class FreetypeHandle {
  11. friend FreetypeHandle * initializeFreetype();
  12. friend void deinitializeFreetype(FreetypeHandle *library);
  13. friend FontHandle * loadFont(FreetypeHandle *library, const char *filename);
  14. friend FontHandle * loadFontData(FreetypeHandle *library, const byte *data, int length);
  15. FT_Library library;
  16. };
  17. class FontHandle {
  18. friend FontHandle * adoptFreetypeFont(FT_Face ftFace);
  19. friend FontHandle * loadFont(FreetypeHandle *library, const char *filename);
  20. friend FontHandle * loadFontData(FreetypeHandle *library, const byte *data, int length);
  21. friend void destroyFont(FontHandle *font);
  22. friend bool getFontMetrics(FontMetrics &metrics, FontHandle *font);
  23. friend bool getFontWhitespaceWidth(double &spaceAdvance, double &tabAdvance, FontHandle *font);
  24. friend bool getGlyphIndex(GlyphIndex &glyphIndex, FontHandle *font, unicode_t unicode);
  25. friend bool loadGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, double *advance);
  26. friend bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, double *advance);
  27. friend bool getKerning(double &output, FontHandle *font, GlyphIndex glyphIndex1, GlyphIndex glyphIndex2);
  28. friend bool getKerning(double &output, FontHandle *font, unicode_t unicode1, unicode_t unicode2);
  29. FT_Face face;
  30. bool ownership;
  31. };
  32. struct FtContext {
  33. Point2 position;
  34. Shape *shape;
  35. Contour *contour;
  36. };
  37. static Point2 ftPoint2(const FT_Vector &vector) {
  38. return Point2(F26DOT6_TO_DOUBLE(vector.x), F26DOT6_TO_DOUBLE(vector.y));
  39. }
  40. static int ftMoveTo(const FT_Vector *to, void *user) {
  41. FtContext *context = reinterpret_cast<FtContext *>(user);
  42. if (!(context->contour && context->contour->edges.empty()))
  43. context->contour = &context->shape->addContour();
  44. context->position = ftPoint2(*to);
  45. return 0;
  46. }
  47. static int ftLineTo(const FT_Vector *to, void *user) {
  48. FtContext *context = reinterpret_cast<FtContext *>(user);
  49. Point2 endpoint = ftPoint2(*to);
  50. if (endpoint != context->position) {
  51. context->contour->addEdge(new LinearSegment(context->position, endpoint));
  52. context->position = endpoint;
  53. }
  54. return 0;
  55. }
  56. static int ftConicTo(const FT_Vector *control, const FT_Vector *to, void *user) {
  57. FtContext *context = reinterpret_cast<FtContext *>(user);
  58. context->contour->addEdge(new QuadraticSegment(context->position, ftPoint2(*control), ftPoint2(*to)));
  59. context->position = ftPoint2(*to);
  60. return 0;
  61. }
  62. static int ftCubicTo(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) {
  63. FtContext *context = reinterpret_cast<FtContext *>(user);
  64. context->contour->addEdge(new CubicSegment(context->position, ftPoint2(*control1), ftPoint2(*control2), ftPoint2(*to)));
  65. context->position = ftPoint2(*to);
  66. return 0;
  67. }
  68. GlyphIndex::GlyphIndex(unsigned index) : index(index) { }
  69. unsigned GlyphIndex::getIndex() const {
  70. return index;
  71. }
  72. bool GlyphIndex::operator!() const {
  73. return index == 0;
  74. }
  75. FreetypeHandle * initializeFreetype() {
  76. FreetypeHandle *handle = new FreetypeHandle;
  77. FT_Error error = FT_Init_FreeType(&handle->library);
  78. if (error) {
  79. delete handle;
  80. return NULL;
  81. }
  82. return handle;
  83. }
  84. void deinitializeFreetype(FreetypeHandle *library) {
  85. FT_Done_FreeType(library->library);
  86. delete library;
  87. }
  88. FontHandle * adoptFreetypeFont(FT_Face ftFace) {
  89. FontHandle *handle = new FontHandle;
  90. handle->face = ftFace;
  91. handle->ownership = false;
  92. return handle;
  93. }
  94. FontHandle * loadFont(FreetypeHandle *library, const char *filename) {
  95. if (!library)
  96. return NULL;
  97. FontHandle *handle = new FontHandle;
  98. FT_Error error = FT_New_Face(library->library, filename, 0, &handle->face);
  99. if (error) {
  100. delete handle;
  101. return NULL;
  102. }
  103. handle->ownership = true;
  104. return handle;
  105. }
  106. FontHandle * loadFontData(FreetypeHandle *library, const byte *data, int length) {
  107. if (!library)
  108. return NULL;
  109. FontHandle *handle = new FontHandle;
  110. FT_Error error = FT_New_Memory_Face(library->library, data, length, 0, &handle->face);
  111. if (error) {
  112. delete handle;
  113. return NULL;
  114. }
  115. handle->ownership = true;
  116. return handle;
  117. }
  118. void destroyFont(FontHandle *font) {
  119. if (font->ownership)
  120. FT_Done_Face(font->face);
  121. delete font;
  122. }
  123. bool getFontMetrics(FontMetrics &metrics, FontHandle *font) {
  124. metrics.emSize = F26DOT6_TO_DOUBLE(font->face->units_per_EM);
  125. metrics.ascenderY = F26DOT6_TO_DOUBLE(font->face->ascender);
  126. metrics.descenderY = F26DOT6_TO_DOUBLE(font->face->descender);
  127. metrics.lineHeight = F26DOT6_TO_DOUBLE(font->face->height);
  128. metrics.underlineY = F26DOT6_TO_DOUBLE(font->face->underline_position);
  129. metrics.underlineThickness = F26DOT6_TO_DOUBLE(font->face->underline_thickness);
  130. return true;
  131. }
  132. bool getFontWhitespaceWidth(double &spaceAdvance, double &tabAdvance, FontHandle *font) {
  133. FT_Error error = FT_Load_Char(font->face, ' ', FT_LOAD_NO_SCALE);
  134. if (error)
  135. return false;
  136. spaceAdvance = F26DOT6_TO_DOUBLE(font->face->glyph->advance.x);
  137. error = FT_Load_Char(font->face, '\t', FT_LOAD_NO_SCALE);
  138. if (error)
  139. return false;
  140. tabAdvance = F26DOT6_TO_DOUBLE(font->face->glyph->advance.x);
  141. return true;
  142. }
  143. bool getGlyphIndex(GlyphIndex &glyphIndex, FontHandle *font, unicode_t unicode) {
  144. glyphIndex = GlyphIndex(FT_Get_Char_Index(font->face, unicode));
  145. return glyphIndex.getIndex() != 0;
  146. }
  147. bool loadGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, double *advance) {
  148. if (!font)
  149. return false;
  150. FT_Error error = FT_Load_Glyph(font->face, glyphIndex.getIndex(), FT_LOAD_NO_SCALE);
  151. if (error)
  152. return false;
  153. output.contours.clear();
  154. output.inverseYAxis = false;
  155. if (advance)
  156. *advance = F26DOT6_TO_DOUBLE(font->face->glyph->advance.x);
  157. FtContext context = { };
  158. context.shape = &output;
  159. FT_Outline_Funcs ftFunctions;
  160. ftFunctions.move_to = &ftMoveTo;
  161. ftFunctions.line_to = &ftLineTo;
  162. ftFunctions.conic_to = &ftConicTo;
  163. ftFunctions.cubic_to = &ftCubicTo;
  164. ftFunctions.shift = 0;
  165. ftFunctions.delta = 0;
  166. error = FT_Outline_Decompose(&font->face->glyph->outline, &ftFunctions, &context);
  167. if (error)
  168. return false;
  169. if (!output.contours.empty() && output.contours.back().edges.empty())
  170. output.contours.pop_back();
  171. return true;
  172. }
  173. bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, double *advance) {
  174. return loadGlyph(output, font, GlyphIndex(FT_Get_Char_Index(font->face, unicode)), advance);
  175. }
  176. bool getKerning(double &output, FontHandle *font, GlyphIndex glyphIndex1, GlyphIndex glyphIndex2) {
  177. FT_Vector kerning;
  178. if (FT_Get_Kerning(font->face, glyphIndex1.getIndex(), glyphIndex2.getIndex(), FT_KERNING_UNSCALED, &kerning)) {
  179. output = 0;
  180. return false;
  181. }
  182. output = F26DOT6_TO_DOUBLE(kerning.x);
  183. return true;
  184. }
  185. bool getKerning(double &output, FontHandle *font, unicode_t unicode1, unicode_t unicode2) {
  186. return getKerning(output, font, GlyphIndex(FT_Get_Char_Index(font->face, unicode1)), GlyphIndex(FT_Get_Char_Index(font->face, unicode2)));
  187. }
  188. }