font_fallback_win.cc 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/gfx/font_fallback_win.h"
  5. #include <algorithm>
  6. #include <map>
  7. #include "base/memory/singleton.h"
  8. #include "base/strings/string_piece.h"
  9. #include "base/strings/string_split.h"
  10. #include "base/strings/string_util.h"
  11. #include "base/strings/utf_string_conversions.h"
  12. #include "base/task/current_thread.h"
  13. #include "base/trace_event/trace_event.h"
  14. #include "base/win/registry.h"
  15. #include "ui/gfx/font.h"
  16. #include "ui/gfx/font_fallback.h"
  17. #include "ui/gfx/font_fallback_skia_impl.h"
  18. #include "ui/gfx/platform_font.h"
  19. namespace gfx {
  20. namespace {
  21. // Queries the registry to get a mapping from font filenames to font names.
  22. void QueryFontsFromRegistry(std::map<std::string, std::string>* map) {
  23. const wchar_t* kFonts =
  24. L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
  25. base::win::RegistryValueIterator it(HKEY_LOCAL_MACHINE, kFonts);
  26. for (; it.Valid(); ++it) {
  27. const std::string filename =
  28. base::ToLowerASCII(base::WideToUTF8(it.Value()));
  29. (*map)[filename] = base::WideToUTF8(it.Name());
  30. }
  31. }
  32. // Fills |font_names| with a list of font families found in the font file at
  33. // |filename|. Takes in a |font_map| from font filename to font families, which
  34. // is filled-in by querying the registry, if empty.
  35. void GetFontNamesFromFilename(const std::string& filename,
  36. std::map<std::string, std::string>* font_map,
  37. std::vector<std::string>* font_names) {
  38. if (font_map->empty())
  39. QueryFontsFromRegistry(font_map);
  40. std::map<std::string, std::string>::const_iterator it =
  41. font_map->find(base::ToLowerASCII(filename));
  42. if (it == font_map->end())
  43. return;
  44. internal::ParseFontFamilyString(it->second, font_names);
  45. }
  46. // Returns true if |text| contains only ASCII digits.
  47. bool ContainsOnlyDigits(const std::string& text) {
  48. return text.find_first_not_of("0123456789") == std::u16string::npos;
  49. }
  50. // Appends a Font with the given |name| and |size| to |fonts| unless the last
  51. // entry is already a font with that name.
  52. void AppendFont(const std::string& name, int size, std::vector<Font>* fonts) {
  53. if (fonts->empty() || fonts->back().GetFontName() != name)
  54. fonts->push_back(Font(name, size));
  55. }
  56. // Queries the registry to get a list of linked fonts for |font|.
  57. void QueryLinkedFontsFromRegistry(const Font& font,
  58. std::map<std::string, std::string>* font_map,
  59. std::vector<Font>* linked_fonts) {
  60. const wchar_t* kSystemLink =
  61. L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink";
  62. base::win::RegKey key;
  63. if (FAILED(key.Open(HKEY_LOCAL_MACHINE, kSystemLink, KEY_READ)))
  64. return;
  65. const std::wstring original_font_name = base::UTF8ToWide(font.GetFontName());
  66. std::vector<std::wstring> values;
  67. if (FAILED(key.ReadValues(original_font_name.c_str(), &values))) {
  68. key.Close();
  69. return;
  70. }
  71. std::string filename;
  72. std::string font_name;
  73. for (size_t i = 0; i < values.size(); ++i) {
  74. internal::ParseFontLinkEntry(
  75. base::WideToUTF8(values[i]), &filename, &font_name);
  76. // If the font name is present, add that directly, otherwise add the
  77. // font names corresponding to the filename.
  78. if (!font_name.empty()) {
  79. AppendFont(font_name, font.GetFontSize(), linked_fonts);
  80. } else if (!filename.empty()) {
  81. std::vector<std::string> filename_fonts;
  82. GetFontNamesFromFilename(filename, font_map, &filename_fonts);
  83. for (const std::string& filename_font : filename_fonts)
  84. AppendFont(filename_font, font.GetFontSize(), linked_fonts);
  85. }
  86. }
  87. key.Close();
  88. }
  89. // CachedFontLinkSettings is a singleton cache of the Windows font settings
  90. // from the registry. It maintains a cached view of the registry's list of
  91. // system fonts and their font link chains.
  92. class CachedFontLinkSettings {
  93. public:
  94. static CachedFontLinkSettings* GetInstance();
  95. CachedFontLinkSettings(const CachedFontLinkSettings&) = delete;
  96. CachedFontLinkSettings& operator=(const CachedFontLinkSettings&) = delete;
  97. // Returns the linked fonts list correspond to |font|. Returned value will
  98. // never be null.
  99. const std::vector<Font>* GetLinkedFonts(const Font& font);
  100. private:
  101. friend struct base::DefaultSingletonTraits<CachedFontLinkSettings>;
  102. CachedFontLinkSettings();
  103. virtual ~CachedFontLinkSettings();
  104. // Map of system fonts, from file names to font families.
  105. std::map<std::string, std::string> cached_system_fonts_;
  106. // Map from font names to vectors of linked fonts.
  107. std::map<std::string, std::vector<Font> > cached_linked_fonts_;
  108. };
  109. // static
  110. CachedFontLinkSettings* CachedFontLinkSettings::GetInstance() {
  111. return base::Singleton<
  112. CachedFontLinkSettings,
  113. base::LeakySingletonTraits<CachedFontLinkSettings>>::get();
  114. }
  115. const std::vector<Font>* CachedFontLinkSettings::GetLinkedFonts(
  116. const Font& font) {
  117. const std::string& font_name = font.GetFontName();
  118. std::map<std::string, std::vector<Font> >::const_iterator it =
  119. cached_linked_fonts_.find(font_name);
  120. if (it != cached_linked_fonts_.end())
  121. return &it->second;
  122. std::vector<Font>* linked_fonts = &cached_linked_fonts_[font_name];
  123. QueryLinkedFontsFromRegistry(font, &cached_system_fonts_, linked_fonts);
  124. return linked_fonts;
  125. }
  126. CachedFontLinkSettings::CachedFontLinkSettings() {
  127. }
  128. CachedFontLinkSettings::~CachedFontLinkSettings() {
  129. }
  130. } // namespace
  131. namespace internal {
  132. void ParseFontLinkEntry(const std::string& entry,
  133. std::string* filename,
  134. std::string* font_name) {
  135. std::vector<std::string> parts = base::SplitString(
  136. entry, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
  137. filename->clear();
  138. font_name->clear();
  139. if (parts.size() > 0)
  140. *filename = parts[0];
  141. // The second entry may be the font name or the first scaling factor, if the
  142. // entry does not contain a font name. If it contains only digits, assume it
  143. // is a scaling factor.
  144. if (parts.size() > 1 && !ContainsOnlyDigits(parts[1]))
  145. *font_name = parts[1];
  146. }
  147. void ParseFontFamilyString(const std::string& family,
  148. std::vector<std::string>* font_names) {
  149. // The entry is comma separated, having the font filename as the first value
  150. // followed optionally by the font family name and a pair of integer scaling
  151. // factors.
  152. // TODO(asvitkine): Should we support these scaling factors?
  153. *font_names = base::SplitString(family, "&", base::TRIM_WHITESPACE,
  154. base::SPLIT_WANT_ALL);
  155. if (!font_names->empty()) {
  156. const size_t index = font_names->back().find('(');
  157. if (index != std::string::npos) {
  158. font_names->back().resize(index);
  159. base::TrimWhitespaceASCII(font_names->back(), base::TRIM_TRAILING,
  160. &font_names->back());
  161. }
  162. }
  163. }
  164. } // namespace internal
  165. std::vector<Font> GetFallbackFonts(const Font& font) {
  166. TRACE_EVENT0("fonts", "gfx::GetFallbackFonts");
  167. std::string font_family = font.GetFontName();
  168. CachedFontLinkSettings* font_link = CachedFontLinkSettings::GetInstance();
  169. // GetLinkedFonts doesn't care about the font size, so we always pass 10.
  170. return *font_link->GetLinkedFonts(Font(font_family, 10));
  171. }
  172. bool GetFallbackFont(const Font& font,
  173. const std::string& locale,
  174. base::StringPiece16 text,
  175. Font* result) {
  176. TRACE_EVENT0("fonts", "gfx::GetFallbackFont");
  177. // Creating a DirectWrite font fallback can be expensive. It's ok in the
  178. // browser process because we can use the shared system fallback, but in the
  179. // renderer this can cause hangs. Code that needs font fallback in the
  180. // renderer should instead use the font proxy.
  181. DCHECK(base::CurrentUIThread::IsSet());
  182. // The text passed must be at least length 1.
  183. if (text.empty())
  184. return false;
  185. // Check that we have at least as much text as was claimed. If we have less
  186. // text than expected then DirectWrite will become confused and crash. This
  187. // shouldn't happen, but crbug.com/624905 shows that it happens sometimes.
  188. constexpr char16_t kNulCharacter = '\0';
  189. if (text.find(kNulCharacter) != base::StringPiece16::npos)
  190. return false;
  191. sk_sp<SkTypeface> fallback_typeface =
  192. GetSkiaFallbackTypeface(font, locale, text);
  193. if (!fallback_typeface)
  194. return false;
  195. // Fallback needs to keep the exact SkTypeface, as re-matching the font using
  196. // family name and styling information loses access to the underlying platform
  197. // font handles and is not guaranteed to result in the correct typeface, see
  198. // https://crbug.com/1003829
  199. *result = Font(PlatformFont::CreateFromSkTypeface(
  200. std::move(fallback_typeface), font.GetFontSize(), absl::nullopt));
  201. return true;
  202. }
  203. } // namespace gfx