find-font.c 4.5 KB

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