FontDatabase.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/FlyString.h>
  7. #include <AK/NonnullRefPtrVector.h>
  8. #include <AK/QuickSort.h>
  9. #include <LibCore/DirIterator.h>
  10. #include <LibGfx/Font/Font.h>
  11. #include <LibGfx/Font/FontDatabase.h>
  12. #include <LibGfx/Font/TrueType/Font.h>
  13. #include <LibGfx/Font/Typeface.h>
  14. #include <LibGfx/Font/WOFF/Font.h>
  15. #include <stdlib.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 String s_default_font_query;
  24. static RefPtr<Font> s_fixed_width_font;
  25. static String s_fixed_width_font_query;
  26. static String s_default_fonts_lookup_path = "/res/fonts";
  27. void FontDatabase::set_default_font_query(String query)
  28. {
  29. if (s_default_font_query == query)
  30. return;
  31. s_default_font_query = move(query);
  32. s_default_font = nullptr;
  33. }
  34. String FontDatabase::default_font_query()
  35. {
  36. return s_default_font_query;
  37. }
  38. void FontDatabase::set_default_fonts_lookup_path(String path)
  39. {
  40. if (s_default_fonts_lookup_path == path)
  41. return;
  42. s_default_fonts_lookup_path = move(path);
  43. }
  44. String FontDatabase::default_fonts_lookup_path()
  45. {
  46. return s_default_fonts_lookup_path;
  47. }
  48. Font& FontDatabase::default_font()
  49. {
  50. if (!s_default_font) {
  51. VERIFY(!s_default_font_query.is_empty());
  52. s_default_font = FontDatabase::the().get_by_name(s_default_font_query);
  53. VERIFY(s_default_font);
  54. }
  55. return *s_default_font;
  56. }
  57. void FontDatabase::set_fixed_width_font_query(String query)
  58. {
  59. if (s_fixed_width_font_query == query)
  60. return;
  61. s_fixed_width_font_query = move(query);
  62. s_fixed_width_font = nullptr;
  63. }
  64. String FontDatabase::fixed_width_font_query()
  65. {
  66. return s_fixed_width_font_query;
  67. }
  68. Font& FontDatabase::default_fixed_width_font()
  69. {
  70. if (!s_fixed_width_font) {
  71. VERIFY(!s_fixed_width_font_query.is_empty());
  72. s_fixed_width_font = FontDatabase::the().get_by_name(s_fixed_width_font_query);
  73. VERIFY(s_fixed_width_font);
  74. }
  75. return *s_fixed_width_font;
  76. }
  77. struct FontDatabase::Private {
  78. HashMap<String, NonnullRefPtr<Gfx::Font>> full_name_to_font_map;
  79. Vector<RefPtr<Typeface>> typefaces;
  80. };
  81. FontDatabase::FontDatabase()
  82. : m_private(make<Private>())
  83. {
  84. Core::DirIterator dir_iterator(s_default_fonts_lookup_path, Core::DirIterator::SkipDots);
  85. if (dir_iterator.has_error()) {
  86. warnln("DirIterator: {}", dir_iterator.error_string());
  87. exit(1);
  88. }
  89. while (dir_iterator.has_next()) {
  90. auto path = dir_iterator.next_full_path();
  91. if (path.ends_with(".font"sv)) {
  92. if (auto font = Gfx::BitmapFont::load_from_file(path)) {
  93. m_private->full_name_to_font_map.set(font->qualified_name(), *font);
  94. auto typeface = get_or_create_typeface(font->family(), font->variant());
  95. typeface->add_bitmap_font(font);
  96. }
  97. } else if (path.ends_with(".ttf"sv)) {
  98. // FIXME: What about .otf
  99. if (auto font_or_error = TTF::Font::try_load_from_file(path); !font_or_error.is_error()) {
  100. auto font = font_or_error.release_value();
  101. auto typeface = get_or_create_typeface(font->family(), font->variant());
  102. typeface->set_vector_font(move(font));
  103. }
  104. } else if (path.ends_with(".woff"sv)) {
  105. if (auto font_or_error = WOFF::Font::try_load_from_file(path); !font_or_error.is_error()) {
  106. auto font = font_or_error.release_value();
  107. auto typeface = get_or_create_typeface(font->family(), font->variant());
  108. typeface->set_vector_font(move(font));
  109. }
  110. }
  111. }
  112. }
  113. void FontDatabase::for_each_font(Function<void(Gfx::Font const&)> callback)
  114. {
  115. Vector<RefPtr<Gfx::Font>> fonts;
  116. fonts.ensure_capacity(m_private->full_name_to_font_map.size());
  117. for (auto& it : m_private->full_name_to_font_map)
  118. fonts.append(it.value);
  119. quick_sort(fonts, [](auto& a, auto& b) { return a->qualified_name() < b->qualified_name(); });
  120. for (auto& font : fonts)
  121. callback(*font);
  122. }
  123. void FontDatabase::for_each_fixed_width_font(Function<void(Gfx::Font const&)> callback)
  124. {
  125. Vector<RefPtr<Gfx::Font>> fonts;
  126. fonts.ensure_capacity(m_private->full_name_to_font_map.size());
  127. for (auto& it : m_private->full_name_to_font_map) {
  128. if (it.value->is_fixed_width())
  129. fonts.append(it.value);
  130. }
  131. quick_sort(fonts, [](auto& a, auto& b) { return a->qualified_name() < b->qualified_name(); });
  132. for (auto& font : fonts)
  133. callback(*font);
  134. }
  135. RefPtr<Gfx::Font> FontDatabase::get_by_name(StringView name)
  136. {
  137. auto it = m_private->full_name_to_font_map.find(name);
  138. if (it == m_private->full_name_to_font_map.end()) {
  139. auto parts = name.split_view(" "sv);
  140. if (parts.size() >= 4) {
  141. auto slope = parts.take_last().to_int().value_or(0);
  142. auto weight = parts.take_last().to_int().value_or(0);
  143. auto size = parts.take_last().to_int().value_or(0);
  144. auto family = String::join(' ', parts);
  145. return get(family, size, weight, slope);
  146. }
  147. dbgln("Font lookup failed: '{}'", name);
  148. return nullptr;
  149. }
  150. return it->value;
  151. }
  152. RefPtr<Gfx::Font> FontDatabase::get(FlyString const& family, float point_size, unsigned weight, unsigned slope, Font::AllowInexactSizeMatch allow_inexact_size_match)
  153. {
  154. for (auto typeface : m_private->typefaces) {
  155. if (typeface->family() == family && typeface->weight() == weight && typeface->slope() == slope)
  156. return typeface->get_font(point_size, allow_inexact_size_match);
  157. }
  158. return nullptr;
  159. }
  160. RefPtr<Gfx::Font> FontDatabase::get(FlyString const& family, FlyString const& variant, float point_size, Font::AllowInexactSizeMatch allow_inexact_size_match)
  161. {
  162. for (auto typeface : m_private->typefaces) {
  163. if (typeface->family() == family && typeface->variant() == variant)
  164. return typeface->get_font(point_size, allow_inexact_size_match);
  165. }
  166. return nullptr;
  167. }
  168. RefPtr<Typeface> FontDatabase::get_or_create_typeface(String const& family, String const& variant)
  169. {
  170. for (auto typeface : m_private->typefaces) {
  171. if (typeface->family() == family && typeface->variant() == variant)
  172. return typeface;
  173. }
  174. auto typeface = adopt_ref(*new Typeface(family, variant));
  175. m_private->typefaces.append(typeface);
  176. return typeface;
  177. }
  178. void FontDatabase::for_each_typeface(Function<void(Typeface const&)> callback)
  179. {
  180. for (auto typeface : m_private->typefaces) {
  181. callback(*typeface);
  182. }
  183. }
  184. }