FontDatabase.cpp 6.2 KB

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