FontDatabase.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/DeprecatedFlyString.h>
  7. #include <AK/Queue.h>
  8. #include <AK/QuickSort.h>
  9. #include <LibCore/DirIterator.h>
  10. #include <LibFileSystem/FileSystem.h>
  11. #include <LibGfx/Font/Font.h>
  12. #include <LibGfx/Font/FontDatabase.h>
  13. #include <LibGfx/Font/OpenType/Font.h>
  14. #include <LibGfx/Font/Typeface.h>
  15. #include <LibGfx/Font/WOFF/Font.h>
  16. namespace Gfx {
  17. FontDatabase& FontDatabase::the()
  18. {
  19. static FontDatabase s_the;
  20. return s_the;
  21. }
  22. static RefPtr<Font> s_default_font;
  23. static DeprecatedString s_default_font_query;
  24. static RefPtr<Font> s_window_title_font;
  25. static DeprecatedString s_window_title_font_query;
  26. static RefPtr<Font> s_fixed_width_font;
  27. static DeprecatedString s_fixed_width_font_query;
  28. static DeprecatedString s_default_fonts_lookup_path = "/res/fonts";
  29. void FontDatabase::set_default_font_query(DeprecatedString query)
  30. {
  31. if (s_default_font_query == query)
  32. return;
  33. s_default_font_query = move(query);
  34. s_default_font = nullptr;
  35. }
  36. DeprecatedString FontDatabase::default_font_query()
  37. {
  38. return s_default_font_query;
  39. }
  40. void FontDatabase::set_window_title_font_query(DeprecatedString query)
  41. {
  42. if (s_window_title_font_query == query)
  43. return;
  44. s_window_title_font_query = move(query);
  45. s_window_title_font = nullptr;
  46. }
  47. DeprecatedString FontDatabase::window_title_font_query()
  48. {
  49. return s_window_title_font_query;
  50. }
  51. void FontDatabase::set_default_fonts_lookup_path(DeprecatedString path)
  52. {
  53. if (s_default_fonts_lookup_path == path)
  54. return;
  55. s_default_fonts_lookup_path = move(path);
  56. }
  57. DeprecatedString FontDatabase::default_fonts_lookup_path()
  58. {
  59. return s_default_fonts_lookup_path;
  60. }
  61. Font& FontDatabase::default_font()
  62. {
  63. if (!s_default_font) {
  64. VERIFY(!s_default_font_query.is_empty());
  65. s_default_font = FontDatabase::the().get_by_name(s_default_font_query);
  66. VERIFY(s_default_font);
  67. }
  68. return *s_default_font;
  69. }
  70. Font& FontDatabase::window_title_font()
  71. {
  72. if (!s_window_title_font) {
  73. VERIFY(!s_window_title_font_query.is_empty());
  74. s_window_title_font = FontDatabase::the().get_by_name(s_window_title_font_query);
  75. VERIFY(s_window_title_font);
  76. }
  77. return *s_window_title_font;
  78. }
  79. void FontDatabase::set_fixed_width_font_query(DeprecatedString query)
  80. {
  81. if (s_fixed_width_font_query == query)
  82. return;
  83. s_fixed_width_font_query = move(query);
  84. s_fixed_width_font = nullptr;
  85. }
  86. DeprecatedString FontDatabase::fixed_width_font_query()
  87. {
  88. return s_fixed_width_font_query;
  89. }
  90. Font& FontDatabase::default_fixed_width_font()
  91. {
  92. if (!s_fixed_width_font) {
  93. VERIFY(!s_fixed_width_font_query.is_empty());
  94. s_fixed_width_font = FontDatabase::the().get_by_name(s_fixed_width_font_query);
  95. VERIFY(s_fixed_width_font);
  96. }
  97. return *s_fixed_width_font;
  98. }
  99. struct FontDatabase::Private {
  100. HashMap<DeprecatedString, NonnullRefPtr<Gfx::Font>, CaseInsensitiveStringTraits> full_name_to_font_map;
  101. HashMap<DeprecatedFlyString, Vector<NonnullRefPtr<Typeface>>, CaseInsensitiveStringTraits> typefaces;
  102. };
  103. void FontDatabase::load_all_fonts_from_path(DeprecatedString const& root)
  104. {
  105. Queue<DeprecatedString> path_queue;
  106. path_queue.enqueue(root);
  107. while (!path_queue.is_empty()) {
  108. auto current_directory = path_queue.dequeue();
  109. Core::DirIterator dir_iterator(current_directory, Core::DirIterator::SkipParentAndBaseDir);
  110. if (dir_iterator.has_error()) {
  111. dbgln("FontDatabase::load_all_fonts_from_path('{}'): {}", root, dir_iterator.error());
  112. continue;
  113. }
  114. while (dir_iterator.has_next()) {
  115. auto path = dir_iterator.next_full_path();
  116. if (FileSystem::is_directory(path)) {
  117. path_queue.enqueue(path);
  118. continue;
  119. }
  120. if (path.ends_with(".font"sv)) {
  121. if (auto font_or_error = Gfx::BitmapFont::try_load_from_file(path); !font_or_error.is_error()) {
  122. auto font = font_or_error.release_value();
  123. m_private->full_name_to_font_map.set(font->qualified_name(), *font);
  124. auto typeface = get_or_create_typeface(font->family(), font->variant());
  125. typeface->add_bitmap_font(font);
  126. }
  127. } else if (path.ends_with(".ttf"sv)) {
  128. // FIXME: What about .otf
  129. if (auto font_or_error = OpenType::Font::try_load_from_file(path); !font_or_error.is_error()) {
  130. auto font = font_or_error.release_value();
  131. auto typeface = get_or_create_typeface(font->family(), font->variant());
  132. typeface->set_vector_font(move(font));
  133. }
  134. } else if (path.ends_with(".woff"sv)) {
  135. if (auto font_or_error = WOFF::Font::try_load_from_file(path); !font_or_error.is_error()) {
  136. auto font = font_or_error.release_value();
  137. auto typeface = get_or_create_typeface(font->family(), font->variant());
  138. typeface->set_vector_font(move(font));
  139. }
  140. }
  141. }
  142. }
  143. }
  144. FontDatabase::FontDatabase()
  145. : m_private(make<Private>())
  146. {
  147. load_all_fonts_from_path(s_default_fonts_lookup_path);
  148. }
  149. void FontDatabase::for_each_font(Function<void(Gfx::Font const&)> callback)
  150. {
  151. Vector<RefPtr<Gfx::Font>> fonts;
  152. fonts.ensure_capacity(m_private->full_name_to_font_map.size());
  153. for (auto& it : m_private->full_name_to_font_map)
  154. fonts.append(it.value);
  155. quick_sort(fonts, [](auto& a, auto& b) { return a->qualified_name() < b->qualified_name(); });
  156. for (auto& font : fonts)
  157. callback(*font);
  158. }
  159. void FontDatabase::for_each_fixed_width_font(Function<void(Gfx::Font const&)> callback)
  160. {
  161. Vector<RefPtr<Gfx::Font>> fonts;
  162. fonts.ensure_capacity(m_private->full_name_to_font_map.size());
  163. for (auto& it : m_private->full_name_to_font_map) {
  164. if (it.value->is_fixed_width())
  165. fonts.append(it.value);
  166. }
  167. quick_sort(fonts, [](auto& a, auto& b) { return a->qualified_name() < b->qualified_name(); });
  168. for (auto& font : fonts)
  169. callback(*font);
  170. }
  171. RefPtr<Gfx::Font> FontDatabase::get_by_name(StringView name)
  172. {
  173. auto it = m_private->full_name_to_font_map.find(name);
  174. if (it == m_private->full_name_to_font_map.end()) {
  175. auto parts = name.split_view(" "sv);
  176. if (parts.size() >= 4) {
  177. auto slope = parts.take_last().to_int().value_or(0);
  178. auto weight = parts.take_last().to_int().value_or(0);
  179. auto size = parts.take_last().to_int().value_or(0);
  180. auto family = DeprecatedString::join(' ', parts);
  181. return get(family, size, weight, Gfx::FontWidth::Normal, slope);
  182. }
  183. dbgln("Font lookup failed: '{}'", name);
  184. return nullptr;
  185. }
  186. return it->value;
  187. }
  188. RefPtr<Gfx::Font> FontDatabase::get(DeprecatedFlyString const& family, float point_size, unsigned weight, unsigned width, unsigned slope, Font::AllowInexactSizeMatch allow_inexact_size_match)
  189. {
  190. auto it = m_private->typefaces.find(family);
  191. if (it == m_private->typefaces.end())
  192. return nullptr;
  193. for (auto const& typeface : it->value) {
  194. if (typeface->weight() == weight && typeface->width() == width && typeface->slope() == slope)
  195. return typeface->get_font(point_size, allow_inexact_size_match);
  196. }
  197. return nullptr;
  198. }
  199. RefPtr<Gfx::Font> FontDatabase::get(DeprecatedFlyString const& family, DeprecatedFlyString const& variant, float point_size, Font::AllowInexactSizeMatch allow_inexact_size_match)
  200. {
  201. auto it = m_private->typefaces.find(family);
  202. if (it == m_private->typefaces.end())
  203. return nullptr;
  204. for (auto const& typeface : it->value) {
  205. if (typeface->variant() == variant)
  206. return typeface->get_font(point_size, allow_inexact_size_match);
  207. }
  208. return nullptr;
  209. }
  210. RefPtr<Typeface> FontDatabase::get_or_create_typeface(DeprecatedString const& family, DeprecatedString const& variant)
  211. {
  212. auto it = m_private->typefaces.find(family);
  213. if (it != m_private->typefaces.end()) {
  214. for (auto const& typeface : it->value) {
  215. if (typeface->variant() == variant)
  216. return typeface;
  217. }
  218. }
  219. auto typeface = adopt_ref(*new Typeface(family, variant));
  220. m_private->typefaces.ensure(family).append(typeface);
  221. return typeface;
  222. }
  223. void FontDatabase::for_each_typeface(Function<void(Typeface const&)> callback)
  224. {
  225. for (auto const& it : m_private->typefaces) {
  226. for (auto const& jt : it.value) {
  227. callback(*jt);
  228. }
  229. }
  230. }
  231. void FontDatabase::for_each_typeface_with_family_name(String const& family_name, Function<void(Typeface const&)> callback)
  232. {
  233. auto it = m_private->typefaces.find(family_name.bytes_as_string_view());
  234. if (it == m_private->typefaces.end())
  235. return;
  236. for (auto const& typeface : it->value)
  237. callback(*typeface);
  238. }
  239. }