FontDatabase.cpp 9.0 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/FlyString.h>
  8. #include <AK/Queue.h>
  9. #include <AK/QuickSort.h>
  10. #include <LibCore/Resource.h>
  11. #include <LibFileSystem/FileSystem.h>
  12. #include <LibGfx/Font/Font.h>
  13. #include <LibGfx/Font/FontDatabase.h>
  14. #include <LibGfx/Font/OpenType/Font.h>
  15. #include <LibGfx/Font/Typeface.h>
  16. #include <LibGfx/Font/WOFF/Font.h>
  17. namespace Gfx {
  18. FontDatabase& FontDatabase::the()
  19. {
  20. static FontDatabase s_the;
  21. return s_the;
  22. }
  23. static RefPtr<Font> s_default_font;
  24. static DeprecatedString s_default_font_query;
  25. static RefPtr<Font> s_window_title_font;
  26. static DeprecatedString s_window_title_font_query;
  27. static RefPtr<Font> s_fixed_width_font;
  28. static DeprecatedString s_fixed_width_font_query;
  29. static DeprecatedString s_default_fonts_lookup_path = "/res/fonts";
  30. void FontDatabase::set_default_font_query(DeprecatedString query)
  31. {
  32. if (s_default_font_query == query)
  33. return;
  34. s_default_font_query = move(query);
  35. s_default_font = nullptr;
  36. }
  37. DeprecatedString FontDatabase::default_font_query()
  38. {
  39. return s_default_font_query;
  40. }
  41. void FontDatabase::set_window_title_font_query(DeprecatedString query)
  42. {
  43. if (s_window_title_font_query == query)
  44. return;
  45. s_window_title_font_query = move(query);
  46. s_window_title_font = nullptr;
  47. }
  48. DeprecatedString FontDatabase::window_title_font_query()
  49. {
  50. return s_window_title_font_query;
  51. }
  52. void FontDatabase::set_default_fonts_lookup_path(DeprecatedString path)
  53. {
  54. if (s_default_fonts_lookup_path == path)
  55. return;
  56. s_default_fonts_lookup_path = move(path);
  57. }
  58. DeprecatedString FontDatabase::default_fonts_lookup_path()
  59. {
  60. return s_default_fonts_lookup_path;
  61. }
  62. Font& FontDatabase::default_font()
  63. {
  64. if (!s_default_font) {
  65. VERIFY(!s_default_font_query.is_empty());
  66. s_default_font = FontDatabase::the().get_by_name(s_default_font_query);
  67. VERIFY(s_default_font);
  68. }
  69. return *s_default_font;
  70. }
  71. Font& FontDatabase::window_title_font()
  72. {
  73. if (!s_window_title_font) {
  74. VERIFY(!s_window_title_font_query.is_empty());
  75. s_window_title_font = FontDatabase::the().get_by_name(s_window_title_font_query);
  76. VERIFY(s_window_title_font);
  77. }
  78. return *s_window_title_font;
  79. }
  80. void FontDatabase::set_fixed_width_font_query(DeprecatedString query)
  81. {
  82. if (s_fixed_width_font_query == query)
  83. return;
  84. s_fixed_width_font_query = move(query);
  85. s_fixed_width_font = nullptr;
  86. }
  87. DeprecatedString FontDatabase::fixed_width_font_query()
  88. {
  89. return s_fixed_width_font_query;
  90. }
  91. Font& FontDatabase::default_fixed_width_font()
  92. {
  93. if (!s_fixed_width_font) {
  94. VERIFY(!s_fixed_width_font_query.is_empty());
  95. s_fixed_width_font = FontDatabase::the().get_by_name(s_fixed_width_font_query);
  96. VERIFY(s_fixed_width_font);
  97. }
  98. return *s_fixed_width_font;
  99. }
  100. struct FontDatabase::Private {
  101. HashMap<DeprecatedString, NonnullRefPtr<Gfx::Font>, CaseInsensitiveStringTraits> full_name_to_font_map;
  102. HashMap<FlyString, Vector<NonnullRefPtr<Typeface>>, AK::ASCIICaseInsensitiveFlyStringTraits> typefaces;
  103. };
  104. void FontDatabase::load_all_fonts_from_path(DeprecatedString const& path)
  105. {
  106. load_all_fonts_from_uri(MUST(String::formatted("file://{}", path)));
  107. }
  108. void FontDatabase::load_all_fonts_from_uri(StringView uri)
  109. {
  110. auto root_or_error = Core::Resource::load_from_uri(uri);
  111. if (root_or_error.is_error()) {
  112. dbgln("FontDatabase::load_all_fonts_from_uri('{}'): {}", uri, root_or_error.error());
  113. return;
  114. }
  115. auto root = root_or_error.release_value();
  116. root->for_each_descendant_file([this](Core::Resource const& resource) -> IterationDecision {
  117. // FIXME: Use Resources and their bytes/streams throughout so we don't have to use the path here
  118. auto path_string = resource.filesystem_path().release_value();
  119. auto path = path_string.bytes_as_string_view();
  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().to_deprecated_string(), *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. return IterationDecision::Continue;
  142. });
  143. }
  144. FontDatabase::FontDatabase()
  145. : m_private(make<Private>())
  146. {
  147. load_all_fonts_from_uri("resource://fonts"sv);
  148. load_all_fonts_from_path(s_default_fonts_lookup_path);
  149. }
  150. void FontDatabase::for_each_font(Function<void(Gfx::Font const&)> callback)
  151. {
  152. Vector<RefPtr<Gfx::Font>> fonts;
  153. fonts.ensure_capacity(m_private->full_name_to_font_map.size());
  154. for (auto& it : m_private->full_name_to_font_map)
  155. fonts.append(it.value);
  156. quick_sort(fonts, [](auto& a, auto& b) { return a->qualified_name() < b->qualified_name(); });
  157. for (auto& font : fonts)
  158. callback(*font);
  159. }
  160. void FontDatabase::for_each_fixed_width_font(Function<void(Gfx::Font const&)> callback)
  161. {
  162. Vector<RefPtr<Gfx::Font>> fonts;
  163. fonts.ensure_capacity(m_private->full_name_to_font_map.size());
  164. for (auto& it : m_private->full_name_to_font_map) {
  165. if (it.value->is_fixed_width())
  166. fonts.append(it.value);
  167. }
  168. quick_sort(fonts, [](auto& a, auto& b) { return a->qualified_name() < b->qualified_name(); });
  169. for (auto& font : fonts)
  170. callback(*font);
  171. }
  172. RefPtr<Gfx::Font> FontDatabase::get_by_name(StringView name)
  173. {
  174. auto it = m_private->full_name_to_font_map.find(name);
  175. if (it == m_private->full_name_to_font_map.end()) {
  176. auto parts = name.split_view(" "sv);
  177. if (parts.size() >= 4) {
  178. auto slope = parts.take_last().to_int().value_or(0);
  179. auto weight = parts.take_last().to_int().value_or(0);
  180. auto size = parts.take_last().to_int().value_or(0);
  181. auto family = MUST(String::join(' ', parts));
  182. return get(family, size, weight, Gfx::FontWidth::Normal, slope);
  183. }
  184. dbgln("Font lookup failed: '{}'", name);
  185. return nullptr;
  186. }
  187. return it->value;
  188. }
  189. RefPtr<Gfx::Font> FontDatabase::get(FlyString const& family, float point_size, unsigned weight, unsigned width, unsigned slope, Font::AllowInexactSizeMatch allow_inexact_size_match)
  190. {
  191. auto it = m_private->typefaces.find(family);
  192. if (it == m_private->typefaces.end())
  193. return nullptr;
  194. for (auto const& typeface : it->value) {
  195. if (typeface->weight() == weight && typeface->width() == width && typeface->slope() == slope)
  196. return typeface->get_font(point_size, allow_inexact_size_match);
  197. }
  198. return nullptr;
  199. }
  200. RefPtr<Gfx::Font> FontDatabase::get(FlyString const& family, FlyString const& variant, float point_size, Font::AllowInexactSizeMatch allow_inexact_size_match)
  201. {
  202. auto it = m_private->typefaces.find(family);
  203. if (it == m_private->typefaces.end())
  204. return nullptr;
  205. for (auto const& typeface : it->value) {
  206. if (typeface->variant() == variant)
  207. return typeface->get_font(point_size, allow_inexact_size_match);
  208. }
  209. return nullptr;
  210. }
  211. RefPtr<Typeface> FontDatabase::get_or_create_typeface(FlyString const& family, FlyString const& variant)
  212. {
  213. auto it = m_private->typefaces.find(family);
  214. if (it != m_private->typefaces.end()) {
  215. for (auto const& typeface : it->value) {
  216. if (typeface->variant() == variant)
  217. return typeface;
  218. }
  219. }
  220. auto typeface = adopt_ref(*new Typeface(family, variant));
  221. m_private->typefaces.ensure(family).append(typeface);
  222. return typeface;
  223. }
  224. void FontDatabase::for_each_typeface(Function<void(Typeface const&)> callback)
  225. {
  226. for (auto const& it : m_private->typefaces) {
  227. for (auto const& jt : it.value) {
  228. callback(*jt);
  229. }
  230. }
  231. }
  232. void FontDatabase::for_each_typeface_with_family_name(FlyString const& family_name, Function<void(Typeface const&)> callback)
  233. {
  234. auto it = m_private->typefaces.find(family_name);
  235. if (it == m_private->typefaces.end())
  236. return;
  237. for (auto const& typeface : it->value)
  238. callback(*typeface);
  239. }
  240. }