FontProvider.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. #include "FontProvider.h"
  2. #include "../../../Include/RmlUi/Core/Core.h"
  3. #include "../../../Include/RmlUi/Core/FileInterface.h"
  4. #include "../../../Include/RmlUi/Core/Log.h"
  5. #include "../../../Include/RmlUi/Core/Math.h"
  6. #include "../../../Include/RmlUi/Core/StringUtilities.h"
  7. #include "../ComputeProperty.h"
  8. #include "FontFace.h"
  9. #include "FontFamily.h"
  10. #include "FreeTypeInterface.h"
  11. #include <algorithm>
  12. namespace Rml {
  13. static FontProvider* g_font_provider = nullptr;
  14. FontProvider::FontProvider()
  15. {
  16. RMLUI_ASSERT(!g_font_provider);
  17. }
  18. FontProvider::~FontProvider()
  19. {
  20. RMLUI_ASSERT(g_font_provider == this);
  21. }
  22. bool FontProvider::Initialise()
  23. {
  24. RMLUI_ASSERT(!g_font_provider);
  25. if (!FreeType::Initialise())
  26. return false;
  27. g_font_provider = new FontProvider;
  28. return true;
  29. }
  30. void FontProvider::Shutdown()
  31. {
  32. RMLUI_ASSERT(g_font_provider);
  33. delete g_font_provider;
  34. g_font_provider = nullptr;
  35. FreeType::Shutdown();
  36. }
  37. FontProvider& FontProvider::Get()
  38. {
  39. RMLUI_ASSERT(g_font_provider);
  40. return *g_font_provider;
  41. }
  42. FontFaceHandleDefault* FontProvider::GetFontFaceHandle(const String& family, Style::FontStyle style, Style::FontWeight weight, int size)
  43. {
  44. RMLUI_ASSERTMSG(family == StringUtilities::ToLower(family), "Font family name must be converted to lowercase before entering here.");
  45. FontFamilyMap& families = Get().font_families;
  46. auto it = families.find(family);
  47. if (it == families.end())
  48. return nullptr;
  49. return it->second->GetFaceHandle(style, weight, size);
  50. }
  51. int FontProvider::CountFallbackFontFaces()
  52. {
  53. return (int)Get().fallback_font_faces.size();
  54. }
  55. FontFaceHandleDefault* FontProvider::GetFallbackFontFace(int index, int font_size)
  56. {
  57. auto& faces = FontProvider::Get().fallback_font_faces;
  58. if (index >= 0 && index < (int)faces.size())
  59. return faces[index]->GetHandle(font_size, false);
  60. return nullptr;
  61. }
  62. void FontProvider::ReleaseFontResources()
  63. {
  64. RMLUI_ASSERT(g_font_provider);
  65. for (auto& name_family : g_font_provider->font_families)
  66. name_family.second->ReleaseFontResources();
  67. }
  68. bool FontProvider::LoadFontFace(const String& file_name, int face_index, bool fallback_face, Style::FontWeight weight)
  69. {
  70. FileInterface* file_interface = GetFileInterface();
  71. FileHandle handle = file_interface->Open(file_name);
  72. if (!handle)
  73. {
  74. Log::Message(Log::LT_ERROR, "Failed to load font face from %s, could not open file.", file_name.c_str());
  75. return false;
  76. }
  77. size_t length = file_interface->Length(handle);
  78. auto buffer_ptr = UniquePtr<byte[]>(new byte[length]);
  79. byte* buffer = buffer_ptr.get();
  80. file_interface->Read(buffer, length, handle);
  81. file_interface->Close(handle);
  82. bool result = Get().LoadFontFace({buffer, length}, face_index, fallback_face, std::move(buffer_ptr), file_name, {}, Style::FontStyle::Normal, weight);
  83. return result;
  84. }
  85. bool FontProvider::LoadFontFace(Span<const byte> data, int face_index, const String& font_family, Style::FontStyle style, Style::FontWeight weight,
  86. bool fallback_face)
  87. {
  88. const String source = "memory";
  89. bool result = Get().LoadFontFace(data, face_index, fallback_face, nullptr, source, font_family, style, weight);
  90. return result;
  91. }
  92. bool FontProvider::LoadFontFace(Span<const byte> data, int face_index, bool fallback_face, UniquePtr<byte[]> face_memory, const String& source, String font_family,
  93. Style::FontStyle style, Style::FontWeight weight)
  94. {
  95. using Style::FontWeight;
  96. Vector<FaceVariation> face_variations;
  97. if (!FreeType::GetFaceVariations(data, face_variations, face_index))
  98. {
  99. Log::Message(Log::LT_ERROR, "Failed to load font face from '%s': Invalid or unsupported font face file format.", source.c_str());
  100. return false;
  101. }
  102. Vector<FaceVariation> load_variations;
  103. if (face_variations.empty())
  104. {
  105. load_variations.push_back(FaceVariation{Style::FontWeight::Auto, 0, 0});
  106. }
  107. else
  108. {
  109. // Iterate through all the face variations and pick the ones to load. The list is already sorted by (weight, width). When weight is set to
  110. // 'auto' we load all the weights of the face. However, we only want to load one width for each weight.
  111. for (auto it = face_variations.begin(); it != face_variations.end();)
  112. {
  113. if (weight != FontWeight::Auto && it->weight != weight)
  114. {
  115. ++it;
  116. continue;
  117. }
  118. // We don't currently have any way for users to select widths, so we search for a regular (medium) value here.
  119. constexpr int search_width = 100;
  120. const FontWeight current_weight = it->weight;
  121. int best_width_distance = Math::Absolute((int)it->width - search_width);
  122. auto it_best_width = it;
  123. // Search forward to find the best 'width' with the same weight.
  124. for (++it; it != face_variations.end(); ++it)
  125. {
  126. if (it->weight != current_weight)
  127. break;
  128. const int width_distance = Math::Absolute((int)it->width - search_width);
  129. if (width_distance < best_width_distance)
  130. {
  131. best_width_distance = width_distance;
  132. it_best_width = it;
  133. }
  134. }
  135. load_variations.push_back(*it_best_width);
  136. }
  137. }
  138. if (load_variations.empty())
  139. {
  140. Log::Message(Log::LT_ERROR, "Failed to load font face from '%s': Could not locate face with weight %d.", source.c_str(), (int)weight);
  141. return false;
  142. }
  143. for (const FaceVariation& variation : load_variations)
  144. {
  145. FontFaceHandleFreetype ft_face = FreeType::LoadFace(data, source, face_index, variation.named_instance_index);
  146. if (!ft_face)
  147. return false;
  148. if (font_family.empty())
  149. FreeType::GetFaceStyle(ft_face, &font_family, &style, nullptr);
  150. if (weight == FontWeight::Auto)
  151. FreeType::GetFaceStyle(ft_face, nullptr, nullptr, &weight);
  152. const FontWeight variation_weight = (variation.weight == FontWeight::Auto ? weight : variation.weight);
  153. const String font_face_description = GetFontFaceDescription(font_family, style, variation_weight);
  154. if (!AddFace(ft_face, font_family, style, variation_weight, fallback_face, std::move(face_memory)))
  155. {
  156. Log::Message(Log::LT_ERROR, "Failed to load font face %s from '%s'.", font_face_description.c_str(), source.c_str());
  157. return false;
  158. }
  159. Log::Message(Log::LT_INFO, "Loaded font face %s from '%s'.", font_face_description.c_str(), source.c_str());
  160. }
  161. return true;
  162. }
  163. bool FontProvider::AddFace(FontFaceHandleFreetype face, const String& family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face,
  164. UniquePtr<byte[]> face_memory)
  165. {
  166. if (family.empty() || weight == Style::FontWeight::Auto)
  167. return false;
  168. String family_lower = StringUtilities::ToLower(family);
  169. FontFamily* font_family = nullptr;
  170. auto it = font_families.find(family_lower);
  171. if (it != font_families.end())
  172. {
  173. font_family = (FontFamily*)it->second.get();
  174. }
  175. else
  176. {
  177. auto font_family_ptr = MakeUnique<FontFamily>(family_lower);
  178. font_family = font_family_ptr.get();
  179. font_families[family_lower] = std::move(font_family_ptr);
  180. }
  181. FontFace* font_face_result = font_family->AddFace(face, style, weight, std::move(face_memory));
  182. if (font_face_result && fallback_face)
  183. {
  184. auto it_fallback_face = std::find(fallback_font_faces.begin(), fallback_font_faces.end(), font_face_result);
  185. if (it_fallback_face == fallback_font_faces.end())
  186. {
  187. fallback_font_faces.push_back(font_face_result);
  188. }
  189. }
  190. return static_cast<bool>(font_face_result);
  191. }
  192. } // namespace Rml