find-font.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. #include <ctype.h>
  2. #include <obs.h>
  3. #include "find-font.h"
  4. DARRAY(struct font_path_info) font_list;
  5. static void create_bitmap_sizes(struct font_path_info *info, FT_Face face)
  6. {
  7. DARRAY(int) sizes;
  8. if (!info->is_bitmap) {
  9. info->num_sizes = 0;
  10. info->sizes = NULL;
  11. return;
  12. }
  13. da_init(sizes);
  14. da_reserve(sizes, face->num_fixed_sizes);
  15. for (int i = 0; i < face->num_fixed_sizes; i++) {
  16. int val = face->available_sizes[i].size >> 6;
  17. da_push_back(sizes, &val);
  18. }
  19. info->sizes = sizes.array;
  20. info->num_sizes = face->num_fixed_sizes;
  21. }
  22. static void add_font_path(FT_Face face,
  23. FT_Long idx,
  24. const char *family_in,
  25. const char *style_in,
  26. const char *path)
  27. {
  28. struct dstr face_and_style = {0};
  29. struct font_path_info info;
  30. if (!family_in || !path)
  31. return;
  32. dstr_copy(&face_and_style, family_in);
  33. if (face->style_name) {
  34. struct dstr style = {0};
  35. dstr_copy(&style, style_in);
  36. dstr_replace(&style, "Bold", "");
  37. dstr_replace(&style, "Italic", "");
  38. dstr_replace(&style, " ", " ");
  39. dstr_depad(&style);
  40. if (!dstr_is_empty(&style)) {
  41. dstr_cat(&face_and_style, " ");
  42. dstr_cat_dstr(&face_and_style, &style);
  43. }
  44. dstr_free(&style);
  45. }
  46. info.face_and_style = face_and_style.array;
  47. info.full_len = face_and_style.len;
  48. info.face_len = strlen(family_in);
  49. info.is_bitmap = !!(face->face_flags & FT_FACE_FLAG_FIXED_SIZES);
  50. info.bold = !!(face->style_flags & FT_STYLE_FLAG_BOLD);
  51. info.italic = !!(face->style_flags & FT_STYLE_FLAG_ITALIC);
  52. info.index = idx;
  53. info.path = bstrdup(path);
  54. create_bitmap_sizes(&info, face);
  55. da_push_back(font_list, &info);
  56. /*blog(LOG_DEBUG, "name: %s\n\tstyle: %s\n\tpath: %s\n",
  57. family_in,
  58. style_in,
  59. path);*/
  60. }
  61. void build_font_path_info(FT_Face face, FT_Long idx, const char *path)
  62. {
  63. FT_UInt num_names = FT_Get_Sfnt_Name_Count(face);
  64. DARRAY(char*) family_names;
  65. da_init(family_names);
  66. da_push_back(family_names, &face->family_name);
  67. for (FT_UInt i = 0; i < num_names; i++) {
  68. FT_SfntName name;
  69. char *family;
  70. FT_Error ret = FT_Get_Sfnt_Name(face, i, &name);
  71. if (ret != 0 || name.name_id != TT_NAME_ID_FONT_FAMILY)
  72. continue;
  73. family = sfnt_name_to_utf8(&name);
  74. if (!family)
  75. continue;
  76. for (size_t i = 0; i < family_names.num; i++) {
  77. if (astrcmpi(family_names.array[i], family) == 0) {
  78. bfree(family);
  79. family = NULL;
  80. break;
  81. }
  82. }
  83. if (family)
  84. da_push_back(family_names, &family);
  85. }
  86. for (size_t i = 0; i < family_names.num; i++) {
  87. add_font_path(face, idx, family_names.array[i],
  88. face->style_name, path);
  89. /* first item isn't our allocation */
  90. if (i > 0)
  91. bfree(family_names.array[i]);
  92. }
  93. da_free(family_names);
  94. }
  95. void free_os_font_list(void)
  96. {
  97. for (size_t i = 0; i < font_list.num; i++)
  98. font_path_info_free(font_list.array + i);
  99. da_free(font_list);
  100. }
  101. static inline size_t get_rating(struct font_path_info *info, struct dstr *cmp)
  102. {
  103. const char *src = info->face_and_style;
  104. const char *dst = cmp->array;
  105. size_t num = 0;
  106. do {
  107. char ch1 = (char)toupper(*src);
  108. char ch2 = (char)toupper(*dst);
  109. if (ch1 != ch2)
  110. break;
  111. num++;
  112. } while (*src++ && *dst++);
  113. return num;
  114. }
  115. const char *get_font_path(const char *family, uint16_t size, const char *style,
  116. uint32_t flags, FT_Long *idx)
  117. {
  118. const char *best_path = NULL;
  119. double best_rating = 0.0;
  120. struct dstr face_and_style = {0};
  121. struct dstr style_str = {0};
  122. bool bold = !!(flags & OBS_FONT_BOLD);
  123. bool italic = !!(flags & OBS_FONT_ITALIC);
  124. if (!family || !*family)
  125. return NULL;
  126. if (style) {
  127. dstr_copy(&style_str, style);
  128. dstr_replace(&style_str, "Bold", "");
  129. dstr_replace(&style_str, "Italic", "");
  130. dstr_replace(&style_str, " ", " ");
  131. dstr_depad(&style_str);
  132. }
  133. dstr_copy(&face_and_style, family);
  134. if (!dstr_is_empty(&style_str)) {
  135. dstr_cat(&face_and_style, " ");
  136. dstr_cat_dstr(&face_and_style, &style_str);
  137. }
  138. for (size_t i = 0; i < font_list.num; i++) {
  139. struct font_path_info *info = font_list.array + i;
  140. double rating = (double)get_rating(info, &face_and_style);
  141. if (rating < info->face_len)
  142. continue;
  143. if (info->is_bitmap) {
  144. int best_diff = 1000;
  145. for (size_t j = 0; j < info->num_sizes; j++) {
  146. int diff = abs(info->sizes[j] - size);
  147. if (diff < best_diff)
  148. best_diff = diff;
  149. }
  150. rating /= (double)(best_diff + 1.0);
  151. }
  152. if (info->bold == bold) rating += 1.0;
  153. if (info->italic == italic) rating += 1.0;
  154. if (rating > best_rating) {
  155. best_path = info->path;
  156. *idx = info->index;
  157. best_rating = rating;
  158. }
  159. }
  160. dstr_free(&style_str);
  161. dstr_free(&face_and_style);
  162. return best_path;
  163. }