123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ui/gfx/font_render_params.h"
- #include <fontconfig/fontconfig.h>
- #include <stddef.h>
- #include <stdint.h>
- #include <memory>
- #include "base/command_line.h"
- #include "base/containers/lru_cache.h"
- #include "base/lazy_instance.h"
- #include "base/logging.h"
- #include "base/strings/string_util.h"
- #include "base/strings/stringprintf.h"
- #include "base/synchronization/lock.h"
- #include "base/trace_event/trace_event.h"
- #include "build/build_config.h"
- #include "build/chromeos_buildflags.h"
- #include "ui/gfx/font.h"
- #include "ui/gfx/font_render_params_linux.h"
- #include "ui/gfx/linux/fontconfig_util.h"
- #include "ui/gfx/switches.h"
- #if BUILDFLAG(IS_LINUX)
- #include "ui/linux/linux_ui.h"
- #endif
- namespace gfx {
- namespace {
- int FontWeightToFCWeight(Font::Weight weight) {
- const int weight_number = static_cast<int>(weight);
- if (weight_number <= (static_cast<int>(Font::Weight::THIN) +
- static_cast<int>(Font::Weight::EXTRA_LIGHT)) /
- 2)
- return FC_WEIGHT_THIN;
- else if (weight_number <= (static_cast<int>(Font::Weight::EXTRA_LIGHT) +
- static_cast<int>(Font::Weight::LIGHT)) /
- 2)
- return FC_WEIGHT_ULTRALIGHT;
- else if (weight_number <= (static_cast<int>(Font::Weight::LIGHT) +
- static_cast<int>(Font::Weight::NORMAL)) /
- 2)
- return FC_WEIGHT_LIGHT;
- else if (weight_number <= (static_cast<int>(Font::Weight::NORMAL) +
- static_cast<int>(Font::Weight::MEDIUM)) /
- 2)
- return FC_WEIGHT_NORMAL;
- else if (weight_number <= (static_cast<int>(Font::Weight::MEDIUM) +
- static_cast<int>(Font::Weight::SEMIBOLD)) /
- 2)
- return FC_WEIGHT_MEDIUM;
- else if (weight_number <= (static_cast<int>(Font::Weight::SEMIBOLD) +
- static_cast<int>(Font::Weight::BOLD)) /
- 2)
- return FC_WEIGHT_DEMIBOLD;
- else if (weight_number <= (static_cast<int>(Font::Weight::BOLD) +
- static_cast<int>(Font::Weight::EXTRA_BOLD)) /
- 2)
- return FC_WEIGHT_BOLD;
- else if (weight_number <= (static_cast<int>(Font::Weight::EXTRA_BOLD) +
- static_cast<int>(Font::Weight::BLACK)) /
- 2)
- return FC_WEIGHT_ULTRABOLD;
- else
- return FC_WEIGHT_BLACK;
- }
- // A device scale factor used to determine if subpixel positioning
- // should be used.
- float device_scale_factor_ = 1.0f;
- // Number of recent GetFontRenderParams() results to cache.
- const size_t kCacheSize = 256;
- // Cached result from a call to GetFontRenderParams().
- struct QueryResult {
- QueryResult(const FontRenderParams& params, const std::string& family)
- : params(params), family(family) {}
- ~QueryResult() {}
- FontRenderParams params;
- std::string family;
- };
- // Keyed by hashes of FontRenderParamQuery structs from
- // HashFontRenderParamsQuery().
- typedef base::HashingLRUCache<std::string, QueryResult> Cache;
- // A cache and the lock that must be held while accessing it.
- // GetFontRenderParams() is called by both the UI thread and the sandbox IPC
- // thread.
- struct SynchronizedCache {
- SynchronizedCache() : cache(kCacheSize) {}
- base::Lock lock;
- Cache cache;
- };
- base::LazyInstance<SynchronizedCache>::Leaky g_synchronized_cache =
- LAZY_INSTANCE_INITIALIZER;
- // Serialize |query| into a string value suitable for use as a cache key.
- std::string GetFontRenderParamsQueryKey(const FontRenderParamsQuery& query) {
- return base::StringPrintf(
- "%d|%d|%d|%d|%s|%f", query.pixel_size, query.point_size, query.style,
- static_cast<int>(query.weight),
- base::JoinString(query.families, ",").c_str(), query.device_scale_factor);
- }
- } // namespace
- bool QueryFontconfig(const FontRenderParamsQuery& query,
- FontRenderParams* params_out,
- std::string* family_out) {
- TRACE_EVENT0("fonts", "gfx::QueryFontconfig");
- ScopedFcPattern query_pattern(FcPatternCreate());
- CHECK(query_pattern);
- FcPatternAddBool(query_pattern.get(), FC_SCALABLE, FcTrue);
- for (auto it = query.families.begin(); it != query.families.end(); ++it) {
- FcPatternAddString(query_pattern.get(), FC_FAMILY,
- reinterpret_cast<const FcChar8*>(it->c_str()));
- }
- if (query.pixel_size > 0)
- FcPatternAddDouble(query_pattern.get(), FC_PIXEL_SIZE, query.pixel_size);
- if (query.point_size > 0)
- FcPatternAddInteger(query_pattern.get(), FC_SIZE, query.point_size);
- if (query.style >= 0) {
- FcPatternAddInteger(
- query_pattern.get(), FC_SLANT,
- (query.style & Font::ITALIC) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN);
- }
- if (query.weight != Font::Weight::INVALID) {
- FcPatternAddInteger(query_pattern.get(), FC_WEIGHT,
- FontWeightToFCWeight(query.weight));
- }
- FcConfig* config = GetGlobalFontConfig();
- FcConfigSubstitute(config, query_pattern.get(), FcMatchPattern);
- FcDefaultSubstitute(query_pattern.get());
- ScopedFcPattern result_pattern;
- if (query.is_empty()) {
- // If the query was empty, call FcConfigSubstituteWithPat() to get a
- // non-family- or size-specific configuration so it can be used as the
- // default.
- result_pattern.reset(FcPatternDuplicate(query_pattern.get()));
- if (!result_pattern)
- return false;
- FcPatternDel(result_pattern.get(), FC_FAMILY);
- FcPatternDel(result_pattern.get(), FC_PIXEL_SIZE);
- FcPatternDel(result_pattern.get(), FC_SIZE);
- FcConfigSubstituteWithPat(config, result_pattern.get(), query_pattern.get(),
- FcMatchFont);
- } else {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("fonts"), "FcFontMatch");
- FcResult result;
- result_pattern.reset(FcFontMatch(config, query_pattern.get(), &result));
- if (!result_pattern)
- return false;
- }
- DCHECK(result_pattern);
- if (family_out) {
- FcChar8* family = NULL;
- FcPatternGetString(result_pattern.get(), FC_FAMILY, 0, &family);
- if (family)
- family_out->assign(reinterpret_cast<const char*>(family));
- }
- if (params_out)
- GetFontRenderParamsFromFcPattern(result_pattern.get(), params_out);
- return true;
- }
- FontRenderParams GetFontRenderParams(const FontRenderParamsQuery& query,
- std::string* family_out) {
- TRACE_EVENT0("fonts", "gfx::GetFontRenderParams");
- FontRenderParamsQuery actual_query(query);
- if (actual_query.device_scale_factor == 0)
- actual_query.device_scale_factor = device_scale_factor_;
- std::string query_key = GetFontRenderParamsQueryKey(actual_query);
- SynchronizedCache* synchronized_cache = g_synchronized_cache.Pointer();
- {
- // Try to find a cached result so Fontconfig doesn't need to be queried.
- base::AutoLock lock(synchronized_cache->lock);
- Cache::const_iterator it = synchronized_cache->cache.Get(query_key);
- if (it != synchronized_cache->cache.end()) {
- DVLOG(1) << "Returning cached params for " << query_key;
- const QueryResult& result = it->second;
- if (family_out)
- *family_out = result.family;
- return result.params;
- }
- }
- DVLOG(1) << "Computing params for " << query_key;
- if (family_out)
- family_out->clear();
- // Start with the delegate's settings, but let Fontconfig have the final say.
- FontRenderParams params;
- #if BUILDFLAG(IS_LINUX)
- if (const auto* linux_ui = ui::LinuxUi::instance())
- params = linux_ui->GetDefaultFontRenderParams();
- #endif
- QueryFontconfig(actual_query, ¶ms, family_out);
- if (!params.antialiasing) {
- // Cairo forces full hinting when antialiasing is disabled, since anything
- // less than that looks awful; do the same here. Requesting subpixel
- // rendering or positioning doesn't make sense either.
- params.hinting = FontRenderParams::HINTING_FULL;
- params.subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_NONE;
- params.subpixel_positioning = false;
- } else if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableFontSubpixelPositioning)) {
- #if !BUILDFLAG(IS_CHROMEOS_ASH)
- params.subpixel_positioning = actual_query.device_scale_factor > 1.0f;
- #else
- // We want to enable subpixel positioning for fractional dsf.
- params.subpixel_positioning =
- std::abs(std::round(actual_query.device_scale_factor) -
- actual_query.device_scale_factor) >
- std::numeric_limits<float>::epsilon();
- #endif // !BUILDFLAG(IS_CHROMEOS_ASH)
- // To enable subpixel positioning, we need to disable hinting.
- if (params.subpixel_positioning)
- params.hinting = FontRenderParams::HINTING_NONE;
- }
- // Use the first family from the list if Fontconfig didn't suggest a family.
- if (family_out && family_out->empty() && !actual_query.families.empty())
- *family_out = actual_query.families[0];
- {
- // Store the result. It's fine if this overwrites a result that was cached
- // by a different thread in the meantime; the values should be identical.
- base::AutoLock lock(synchronized_cache->lock);
- synchronized_cache->cache.Put(
- query_key,
- QueryResult(params, family_out ? *family_out : std::string()));
- }
- return params;
- }
- void ClearFontRenderParamsCacheForTest() {
- SynchronizedCache* synchronized_cache = g_synchronized_cache.Pointer();
- base::AutoLock lock(synchronized_cache->lock);
- synchronized_cache->cache.Clear();
- }
- float GetFontRenderParamsDeviceScaleFactor() {
- return device_scale_factor_;
- }
- void SetFontRenderParamsDeviceScaleFactor(float device_scale_factor) {
- device_scale_factor_ = device_scale_factor;
- }
- } // namespace gfx
|