import-font.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. #include "import-font.h"
  2. #include <cstdlib>
  3. #include <queue>
  4. #include <ft2build.h>
  5. #include FT_FREETYPE_H
  6. #ifdef _WIN32
  7. #pragma comment(lib, "freetype.lib")
  8. #endif
  9. namespace msdfgen {
  10. #define REQUIRE(cond) { if (!(cond)) return false; }
  11. class FreetypeHandle {
  12. friend FreetypeHandle * initializeFreetype();
  13. friend void deinitializeFreetype(FreetypeHandle *library);
  14. friend FontHandle * loadFont(FreetypeHandle *library, const char *filename);
  15. FT_Library library;
  16. };
  17. class FontHandle {
  18. friend FontHandle * loadFont(FreetypeHandle *library, const char *filename);
  19. friend void destroyFont(FontHandle *font);
  20. friend bool getFontScale(double &output, FontHandle *font);
  21. friend bool getFontWhitespaceWidth(double &spaceAdvance, double &tabAdvance, FontHandle *font);
  22. friend bool loadGlyph(Shape &output, FontHandle *font, int unicode, double *advance);
  23. friend bool getKerning(double &output, FontHandle *font, int unicode1, int unicode2);
  24. FT_Face face;
  25. };
  26. FreetypeHandle * initializeFreetype() {
  27. FreetypeHandle *handle = new FreetypeHandle;
  28. FT_Error error = FT_Init_FreeType(&handle->library);
  29. if (error) {
  30. delete handle;
  31. return NULL;
  32. }
  33. return handle;
  34. }
  35. void deinitializeFreetype(FreetypeHandle *library) {
  36. FT_Done_FreeType(library->library);
  37. delete library;
  38. }
  39. FontHandle * loadFont(FreetypeHandle *library, const char *filename) {
  40. if (!library)
  41. return NULL;
  42. FontHandle *handle = new FontHandle;
  43. FT_Error error = FT_New_Face(library->library, filename, 0, &handle->face);
  44. if (error) {
  45. delete handle;
  46. return NULL;
  47. }
  48. return handle;
  49. }
  50. void destroyFont(FontHandle *font) {
  51. FT_Done_Face(font->face);
  52. delete font;
  53. }
  54. bool getFontScale(double &output, FontHandle *font) {
  55. output = font->face->units_per_EM/64.;
  56. return true;
  57. }
  58. bool getFontWhitespaceWidth(double &spaceAdvance, double &tabAdvance, FontHandle *font) {
  59. FT_Error error = FT_Load_Char(font->face, ' ', FT_LOAD_NO_SCALE);
  60. if (error)
  61. return false;
  62. spaceAdvance = font->face->glyph->advance.x/64.;
  63. error = FT_Load_Char(font->face, '\t', FT_LOAD_NO_SCALE);
  64. if (error)
  65. return false;
  66. tabAdvance = font->face->glyph->advance.x/64.;
  67. return true;
  68. }
  69. bool loadGlyph(Shape &output, FontHandle *font, int unicode, double *advance) {
  70. enum PointType {
  71. NONE = 0,
  72. PATH_POINT,
  73. QUADRATIC_POINT,
  74. CUBIC_POINT,
  75. CUBIC_POINT2
  76. };
  77. if (!font)
  78. return false;
  79. FT_Error error = FT_Load_Char(font->face, unicode, FT_LOAD_NO_SCALE);
  80. if (error)
  81. return false;
  82. output.contours.clear();
  83. output.inverseYAxis = false;
  84. if (advance)
  85. *advance = font->face->glyph->advance.x/64.;
  86. int last = -1;
  87. // For each contour
  88. for (int i = 0; i < font->face->glyph->outline.n_contours; ++i) {
  89. Contour &contour = output.addContour();
  90. int first = last+1;
  91. last = font->face->glyph->outline.contours[i];
  92. PointType state = NONE;
  93. Point2 startPoint;
  94. Point2 controlPoint[2];
  95. // For each point on the contour
  96. for (int round = 0, index = first; round == 0; ++index) {
  97. // Close contour
  98. if (index > last) {
  99. index = first;
  100. round++;
  101. }
  102. Point2 point(font->face->glyph->outline.points[index].x/64., font->face->glyph->outline.points[index].y/64.);
  103. PointType pointType = font->face->glyph->outline.tags[index]&1 ? PATH_POINT : font->face->glyph->outline.tags[index]&2 ? CUBIC_POINT : QUADRATIC_POINT;
  104. switch (state) {
  105. case NONE:
  106. REQUIRE(pointType == PATH_POINT);
  107. startPoint = point;
  108. state = PATH_POINT;
  109. break;
  110. case PATH_POINT:
  111. if (pointType == PATH_POINT) {
  112. contour.addEdge(new LinearSegment(startPoint, point));
  113. startPoint = point;
  114. } else {
  115. controlPoint[0] = point;
  116. state = pointType;
  117. }
  118. break;
  119. case QUADRATIC_POINT:
  120. REQUIRE(pointType != CUBIC_POINT);
  121. if (pointType == PATH_POINT) {
  122. contour.addEdge(new QuadraticSegment(startPoint, controlPoint[0], point));
  123. startPoint = point;
  124. state = PATH_POINT;
  125. } else {
  126. Point2 midPoint = .5*controlPoint[0]+.5*point;
  127. contour.addEdge(new QuadraticSegment(startPoint, controlPoint[0], midPoint));
  128. startPoint = midPoint;
  129. controlPoint[0] = point;
  130. }
  131. break;
  132. case CUBIC_POINT:
  133. REQUIRE(pointType == CUBIC_POINT);
  134. controlPoint[1] = point;
  135. state = CUBIC_POINT2;
  136. break;
  137. case CUBIC_POINT2:
  138. REQUIRE(pointType != QUADRATIC_POINT);
  139. if (pointType == PATH_POINT) {
  140. contour.addEdge(new CubicSegment(startPoint, controlPoint[0], controlPoint[1], point));
  141. startPoint = point;
  142. } else {
  143. Point2 midPoint = .5*controlPoint[1]+.5*point;
  144. contour.addEdge(new CubicSegment(startPoint, controlPoint[0], controlPoint[1], midPoint));
  145. startPoint = midPoint;
  146. controlPoint[0] = point;
  147. }
  148. state = pointType;
  149. break;
  150. }
  151. }
  152. }
  153. return true;
  154. }
  155. bool getKerning(double &output, FontHandle *font, int unicode1, int unicode2) {
  156. FT_Vector kerning;
  157. if (FT_Get_Kerning(font->face, FT_Get_Char_Index(font->face, unicode1), FT_Get_Char_Index(font->face, unicode2), FT_KERNING_UNSCALED, &kerning)) {
  158. output = 0;
  159. return false;
  160. }
  161. output = kerning.x/64.;
  162. return true;
  163. }
  164. }