font_render_params_linux.cc 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  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_render_params.h"
  5. #include <fontconfig/fontconfig.h>
  6. #include <stddef.h>
  7. #include <stdint.h>
  8. #include <memory>
  9. #include "base/command_line.h"
  10. #include "base/containers/lru_cache.h"
  11. #include "base/lazy_instance.h"
  12. #include "base/logging.h"
  13. #include "base/strings/string_util.h"
  14. #include "base/strings/stringprintf.h"
  15. #include "base/synchronization/lock.h"
  16. #include "base/trace_event/trace_event.h"
  17. #include "build/build_config.h"
  18. #include "build/chromeos_buildflags.h"
  19. #include "ui/gfx/font.h"
  20. #include "ui/gfx/font_render_params_linux.h"
  21. #include "ui/gfx/linux/fontconfig_util.h"
  22. #include "ui/gfx/switches.h"
  23. #if BUILDFLAG(IS_LINUX)
  24. #include "ui/linux/linux_ui.h"
  25. #endif
  26. namespace gfx {
  27. namespace {
  28. int FontWeightToFCWeight(Font::Weight weight) {
  29. const int weight_number = static_cast<int>(weight);
  30. if (weight_number <= (static_cast<int>(Font::Weight::THIN) +
  31. static_cast<int>(Font::Weight::EXTRA_LIGHT)) /
  32. 2)
  33. return FC_WEIGHT_THIN;
  34. else if (weight_number <= (static_cast<int>(Font::Weight::EXTRA_LIGHT) +
  35. static_cast<int>(Font::Weight::LIGHT)) /
  36. 2)
  37. return FC_WEIGHT_ULTRALIGHT;
  38. else if (weight_number <= (static_cast<int>(Font::Weight::LIGHT) +
  39. static_cast<int>(Font::Weight::NORMAL)) /
  40. 2)
  41. return FC_WEIGHT_LIGHT;
  42. else if (weight_number <= (static_cast<int>(Font::Weight::NORMAL) +
  43. static_cast<int>(Font::Weight::MEDIUM)) /
  44. 2)
  45. return FC_WEIGHT_NORMAL;
  46. else if (weight_number <= (static_cast<int>(Font::Weight::MEDIUM) +
  47. static_cast<int>(Font::Weight::SEMIBOLD)) /
  48. 2)
  49. return FC_WEIGHT_MEDIUM;
  50. else if (weight_number <= (static_cast<int>(Font::Weight::SEMIBOLD) +
  51. static_cast<int>(Font::Weight::BOLD)) /
  52. 2)
  53. return FC_WEIGHT_DEMIBOLD;
  54. else if (weight_number <= (static_cast<int>(Font::Weight::BOLD) +
  55. static_cast<int>(Font::Weight::EXTRA_BOLD)) /
  56. 2)
  57. return FC_WEIGHT_BOLD;
  58. else if (weight_number <= (static_cast<int>(Font::Weight::EXTRA_BOLD) +
  59. static_cast<int>(Font::Weight::BLACK)) /
  60. 2)
  61. return FC_WEIGHT_ULTRABOLD;
  62. else
  63. return FC_WEIGHT_BLACK;
  64. }
  65. // A device scale factor used to determine if subpixel positioning
  66. // should be used.
  67. float device_scale_factor_ = 1.0f;
  68. // Number of recent GetFontRenderParams() results to cache.
  69. const size_t kCacheSize = 256;
  70. // Cached result from a call to GetFontRenderParams().
  71. struct QueryResult {
  72. QueryResult(const FontRenderParams& params, const std::string& family)
  73. : params(params), family(family) {}
  74. ~QueryResult() {}
  75. FontRenderParams params;
  76. std::string family;
  77. };
  78. // Keyed by hashes of FontRenderParamQuery structs from
  79. // HashFontRenderParamsQuery().
  80. typedef base::HashingLRUCache<std::string, QueryResult> Cache;
  81. // A cache and the lock that must be held while accessing it.
  82. // GetFontRenderParams() is called by both the UI thread and the sandbox IPC
  83. // thread.
  84. struct SynchronizedCache {
  85. SynchronizedCache() : cache(kCacheSize) {}
  86. base::Lock lock;
  87. Cache cache;
  88. };
  89. base::LazyInstance<SynchronizedCache>::Leaky g_synchronized_cache =
  90. LAZY_INSTANCE_INITIALIZER;
  91. // Serialize |query| into a string value suitable for use as a cache key.
  92. std::string GetFontRenderParamsQueryKey(const FontRenderParamsQuery& query) {
  93. return base::StringPrintf(
  94. "%d|%d|%d|%d|%s|%f", query.pixel_size, query.point_size, query.style,
  95. static_cast<int>(query.weight),
  96. base::JoinString(query.families, ",").c_str(), query.device_scale_factor);
  97. }
  98. } // namespace
  99. bool QueryFontconfig(const FontRenderParamsQuery& query,
  100. FontRenderParams* params_out,
  101. std::string* family_out) {
  102. TRACE_EVENT0("fonts", "gfx::QueryFontconfig");
  103. ScopedFcPattern query_pattern(FcPatternCreate());
  104. CHECK(query_pattern);
  105. FcPatternAddBool(query_pattern.get(), FC_SCALABLE, FcTrue);
  106. for (auto it = query.families.begin(); it != query.families.end(); ++it) {
  107. FcPatternAddString(query_pattern.get(), FC_FAMILY,
  108. reinterpret_cast<const FcChar8*>(it->c_str()));
  109. }
  110. if (query.pixel_size > 0)
  111. FcPatternAddDouble(query_pattern.get(), FC_PIXEL_SIZE, query.pixel_size);
  112. if (query.point_size > 0)
  113. FcPatternAddInteger(query_pattern.get(), FC_SIZE, query.point_size);
  114. if (query.style >= 0) {
  115. FcPatternAddInteger(
  116. query_pattern.get(), FC_SLANT,
  117. (query.style & Font::ITALIC) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN);
  118. }
  119. if (query.weight != Font::Weight::INVALID) {
  120. FcPatternAddInteger(query_pattern.get(), FC_WEIGHT,
  121. FontWeightToFCWeight(query.weight));
  122. }
  123. FcConfig* config = GetGlobalFontConfig();
  124. FcConfigSubstitute(config, query_pattern.get(), FcMatchPattern);
  125. FcDefaultSubstitute(query_pattern.get());
  126. ScopedFcPattern result_pattern;
  127. if (query.is_empty()) {
  128. // If the query was empty, call FcConfigSubstituteWithPat() to get a
  129. // non-family- or size-specific configuration so it can be used as the
  130. // default.
  131. result_pattern.reset(FcPatternDuplicate(query_pattern.get()));
  132. if (!result_pattern)
  133. return false;
  134. FcPatternDel(result_pattern.get(), FC_FAMILY);
  135. FcPatternDel(result_pattern.get(), FC_PIXEL_SIZE);
  136. FcPatternDel(result_pattern.get(), FC_SIZE);
  137. FcConfigSubstituteWithPat(config, result_pattern.get(), query_pattern.get(),
  138. FcMatchFont);
  139. } else {
  140. TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("fonts"), "FcFontMatch");
  141. FcResult result;
  142. result_pattern.reset(FcFontMatch(config, query_pattern.get(), &result));
  143. if (!result_pattern)
  144. return false;
  145. }
  146. DCHECK(result_pattern);
  147. if (family_out) {
  148. FcChar8* family = NULL;
  149. FcPatternGetString(result_pattern.get(), FC_FAMILY, 0, &family);
  150. if (family)
  151. family_out->assign(reinterpret_cast<const char*>(family));
  152. }
  153. if (params_out)
  154. GetFontRenderParamsFromFcPattern(result_pattern.get(), params_out);
  155. return true;
  156. }
  157. FontRenderParams GetFontRenderParams(const FontRenderParamsQuery& query,
  158. std::string* family_out) {
  159. TRACE_EVENT0("fonts", "gfx::GetFontRenderParams");
  160. FontRenderParamsQuery actual_query(query);
  161. if (actual_query.device_scale_factor == 0)
  162. actual_query.device_scale_factor = device_scale_factor_;
  163. std::string query_key = GetFontRenderParamsQueryKey(actual_query);
  164. SynchronizedCache* synchronized_cache = g_synchronized_cache.Pointer();
  165. {
  166. // Try to find a cached result so Fontconfig doesn't need to be queried.
  167. base::AutoLock lock(synchronized_cache->lock);
  168. Cache::const_iterator it = synchronized_cache->cache.Get(query_key);
  169. if (it != synchronized_cache->cache.end()) {
  170. DVLOG(1) << "Returning cached params for " << query_key;
  171. const QueryResult& result = it->second;
  172. if (family_out)
  173. *family_out = result.family;
  174. return result.params;
  175. }
  176. }
  177. DVLOG(1) << "Computing params for " << query_key;
  178. if (family_out)
  179. family_out->clear();
  180. // Start with the delegate's settings, but let Fontconfig have the final say.
  181. FontRenderParams params;
  182. #if BUILDFLAG(IS_LINUX)
  183. if (const auto* linux_ui = ui::LinuxUi::instance())
  184. params = linux_ui->GetDefaultFontRenderParams();
  185. #endif
  186. QueryFontconfig(actual_query, &params, family_out);
  187. if (!params.antialiasing) {
  188. // Cairo forces full hinting when antialiasing is disabled, since anything
  189. // less than that looks awful; do the same here. Requesting subpixel
  190. // rendering or positioning doesn't make sense either.
  191. params.hinting = FontRenderParams::HINTING_FULL;
  192. params.subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_NONE;
  193. params.subpixel_positioning = false;
  194. } else if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
  195. switches::kDisableFontSubpixelPositioning)) {
  196. #if !BUILDFLAG(IS_CHROMEOS_ASH)
  197. params.subpixel_positioning = actual_query.device_scale_factor > 1.0f;
  198. #else
  199. // We want to enable subpixel positioning for fractional dsf.
  200. params.subpixel_positioning =
  201. std::abs(std::round(actual_query.device_scale_factor) -
  202. actual_query.device_scale_factor) >
  203. std::numeric_limits<float>::epsilon();
  204. #endif // !BUILDFLAG(IS_CHROMEOS_ASH)
  205. // To enable subpixel positioning, we need to disable hinting.
  206. if (params.subpixel_positioning)
  207. params.hinting = FontRenderParams::HINTING_NONE;
  208. }
  209. // Use the first family from the list if Fontconfig didn't suggest a family.
  210. if (family_out && family_out->empty() && !actual_query.families.empty())
  211. *family_out = actual_query.families[0];
  212. {
  213. // Store the result. It's fine if this overwrites a result that was cached
  214. // by a different thread in the meantime; the values should be identical.
  215. base::AutoLock lock(synchronized_cache->lock);
  216. synchronized_cache->cache.Put(
  217. query_key,
  218. QueryResult(params, family_out ? *family_out : std::string()));
  219. }
  220. return params;
  221. }
  222. void ClearFontRenderParamsCacheForTest() {
  223. SynchronizedCache* synchronized_cache = g_synchronized_cache.Pointer();
  224. base::AutoLock lock(synchronized_cache->lock);
  225. synchronized_cache->cache.Clear();
  226. }
  227. float GetFontRenderParamsDeviceScaleFactor() {
  228. return device_scale_factor_;
  229. }
  230. void SetFontRenderParamsDeviceScaleFactor(float device_scale_factor) {
  231. device_scale_factor_ = device_scale_factor;
  232. }
  233. } // namespace gfx