import-font.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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. #ifdef _WIN32
  8. #pragma comment(lib, "freetype.lib")
  9. #endif
  10. namespace msdfgen {
  11. #define REQUIRE(cond) { if (!(cond)) return false; }
  12. #define F26DOT6_TO_DOUBLE(x) (1/64.*double(x))
  13. class FreetypeHandle {
  14. friend FreetypeHandle * initializeFreetype();
  15. friend void deinitializeFreetype(FreetypeHandle *library);
  16. friend FontHandle * loadFont(FreetypeHandle *library, const char *filename);
  17. FT_Library library;
  18. };
  19. class FontHandle {
  20. friend FontHandle * loadFont(FreetypeHandle *library, const char *filename);
  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 loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, double *advance);
  25. friend bool getKerning(double &output, FontHandle *font, unicode_t unicode1, unicode_t unicode2);
  26. FT_Face face;
  27. };
  28. struct FtContext {
  29. Point2 position;
  30. Shape *shape;
  31. Contour *contour;
  32. };
  33. static Point2 ftPoint2(const FT_Vector &vector) {
  34. return Point2(F26DOT6_TO_DOUBLE(vector.x), F26DOT6_TO_DOUBLE(vector.y));
  35. }
  36. static int ftMoveTo(const FT_Vector *to, void *user) {
  37. FtContext *context = reinterpret_cast<FtContext *>(user);
  38. if (!(context->contour && context->contour->edges.empty()))
  39. context->contour = &context->shape->addContour();
  40. context->position = ftPoint2(*to);
  41. return 0;
  42. }
  43. static int ftLineTo(const FT_Vector *to, void *user) {
  44. FtContext *context = reinterpret_cast<FtContext *>(user);
  45. Point2 endpoint = ftPoint2(*to);
  46. if (endpoint != context->position) {
  47. context->contour->addEdge(new LinearSegment(context->position, endpoint));
  48. context->position = endpoint;
  49. }
  50. return 0;
  51. }
  52. static int ftConicTo(const FT_Vector *control, const FT_Vector *to, void *user) {
  53. FtContext *context = reinterpret_cast<FtContext *>(user);
  54. context->contour->addEdge(new QuadraticSegment(context->position, ftPoint2(*control), ftPoint2(*to)));
  55. context->position = ftPoint2(*to);
  56. return 0;
  57. }
  58. static int ftCubicTo(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) {
  59. FtContext *context = reinterpret_cast<FtContext *>(user);
  60. context->contour->addEdge(new CubicSegment(context->position, ftPoint2(*control1), ftPoint2(*control2), ftPoint2(*to)));
  61. context->position = ftPoint2(*to);
  62. return 0;
  63. }
  64. FreetypeHandle * initializeFreetype() {
  65. FreetypeHandle *handle = new FreetypeHandle;
  66. FT_Error error = FT_Init_FreeType(&handle->library);
  67. if (error) {
  68. delete handle;
  69. return NULL;
  70. }
  71. return handle;
  72. }
  73. void deinitializeFreetype(FreetypeHandle *library) {
  74. FT_Done_FreeType(library->library);
  75. delete library;
  76. }
  77. FontHandle * loadFont(FreetypeHandle *library, const char *filename) {
  78. if (!library)
  79. return NULL;
  80. FontHandle *handle = new FontHandle;
  81. FT_Error error = FT_New_Face(library->library, filename, 0, &handle->face);
  82. if (error) {
  83. delete handle;
  84. return NULL;
  85. }
  86. return handle;
  87. }
  88. void destroyFont(FontHandle *font) {
  89. FT_Done_Face(font->face);
  90. delete font;
  91. }
  92. bool getFontMetrics(FontMetrics &metrics, FontHandle *font) {
  93. metrics.emSize = F26DOT6_TO_DOUBLE(font->face->units_per_EM);
  94. metrics.ascenderY = F26DOT6_TO_DOUBLE(font->face->ascender);
  95. metrics.descenderY = F26DOT6_TO_DOUBLE(font->face->descender);
  96. metrics.lineHeight = F26DOT6_TO_DOUBLE(font->face->height);
  97. metrics.underlineY = F26DOT6_TO_DOUBLE(font->face->underline_position);
  98. metrics.underlineThickness = F26DOT6_TO_DOUBLE(font->face->underline_thickness);
  99. return true;
  100. }
  101. bool getFontWhitespaceWidth(double &spaceAdvance, double &tabAdvance, FontHandle *font) {
  102. FT_Error error = FT_Load_Char(font->face, ' ', FT_LOAD_NO_SCALE);
  103. if (error)
  104. return false;
  105. spaceAdvance = F26DOT6_TO_DOUBLE(font->face->glyph->advance.x);
  106. error = FT_Load_Char(font->face, '\t', FT_LOAD_NO_SCALE);
  107. if (error)
  108. return false;
  109. tabAdvance = F26DOT6_TO_DOUBLE(font->face->glyph->advance.x);
  110. return true;
  111. }
  112. bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, double *advance) {
  113. if (!font)
  114. return false;
  115. FT_Error error = FT_Load_Char(font->face, unicode, FT_LOAD_NO_SCALE);
  116. if (error)
  117. return false;
  118. output.contours.clear();
  119. output.inverseYAxis = false;
  120. if (advance)
  121. *advance = F26DOT6_TO_DOUBLE(font->face->glyph->advance.x);
  122. FtContext context = { };
  123. context.shape = &output;
  124. FT_Outline_Funcs ftFunctions;
  125. ftFunctions.move_to = &ftMoveTo;
  126. ftFunctions.line_to = &ftLineTo;
  127. ftFunctions.conic_to = &ftConicTo;
  128. ftFunctions.cubic_to = &ftCubicTo;
  129. ftFunctions.shift = 0;
  130. ftFunctions.delta = 0;
  131. error = FT_Outline_Decompose(&font->face->glyph->outline, &ftFunctions, &context);
  132. if (error)
  133. return false;
  134. if (!output.contours.empty() && output.contours.back().edges.empty())
  135. output.contours.pop_back();
  136. return true;
  137. }
  138. bool getKerning(double &output, FontHandle *font, unicode_t unicode1, unicode_t unicode2) {
  139. FT_Vector kerning;
  140. if (FT_Get_Kerning(font->face, FT_Get_Char_Index(font->face, unicode1), FT_Get_Char_Index(font->face, unicode2), FT_KERNING_UNSCALED, &kerning)) {
  141. output = 0;
  142. return false;
  143. }
  144. output = F26DOT6_TO_DOUBLE(kerning.x);
  145. return true;
  146. }
  147. }