Mac: More robust "window under location" for interactive_ui_tests
[chromium-blink-merge.git] / ui / gfx / font_render_params_linux.cc
bloba8305efbe93b826e5abf8a8c3f81e6c2e74feebd
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.
5 #include "ui/gfx/font_render_params.h"
7 #include <fontconfig/fontconfig.h>
9 #include "base/command_line.h"
10 #include "base/containers/mru_cache.h"
11 #include "base/hash.h"
12 #include "base/lazy_instance.h"
13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/synchronization/lock.h"
19 #include "ui/gfx/font.h"
20 #include "ui/gfx/linux_font_delegate.h"
21 #include "ui/gfx/switches.h"
23 namespace gfx {
25 namespace {
27 #if defined(OS_CHROMEOS)
28 // A device scale factor for an internal display (if any)
29 // that is used to determine if subpixel positioning should be used.
30 float device_scale_factor_for_internal_display = 1.0f;
31 #endif
33 // Number of recent GetFontRenderParams() results to cache.
34 const size_t kCacheSize = 64;
36 // Cached result from a call to GetFontRenderParams().
37 struct QueryResult {
38 QueryResult(const FontRenderParams& params, const std::string& family)
39 : params(params),
40 family(family) {
42 ~QueryResult() {}
44 FontRenderParams params;
45 std::string family;
48 // Keyed by hashes of FontRenderParamQuery structs from
49 // HashFontRenderParamsQuery().
50 typedef base::MRUCache<uint32, QueryResult> Cache;
52 // A cache and the lock that must be held while accessing it.
53 // GetFontRenderParams() is called by both the UI thread and the sandbox IPC
54 // thread.
55 struct SynchronizedCache {
56 SynchronizedCache() : cache(kCacheSize) {}
58 base::Lock lock;
59 Cache cache;
62 base::LazyInstance<SynchronizedCache>::Leaky g_synchronized_cache =
63 LAZY_INSTANCE_INITIALIZER;
65 bool IsBrowserTextSubpixelPositioningEnabled(
66 const FontRenderParamsQuery& query) {
67 #if defined(OS_CHROMEOS)
68 return query.device_scale_factor > 1.0f;
69 #else
70 return false;
71 #endif
74 // Converts Fontconfig FC_HINT_STYLE to FontRenderParams::Hinting.
75 FontRenderParams::Hinting ConvertFontconfigHintStyle(int hint_style) {
76 switch (hint_style) {
77 case FC_HINT_SLIGHT: return FontRenderParams::HINTING_SLIGHT;
78 case FC_HINT_MEDIUM: return FontRenderParams::HINTING_MEDIUM;
79 case FC_HINT_FULL: return FontRenderParams::HINTING_FULL;
80 default: return FontRenderParams::HINTING_NONE;
84 // Converts Fontconfig FC_RGBA to FontRenderParams::SubpixelRendering.
85 FontRenderParams::SubpixelRendering ConvertFontconfigRgba(int rgba) {
86 switch (rgba) {
87 case FC_RGBA_RGB: return FontRenderParams::SUBPIXEL_RENDERING_RGB;
88 case FC_RGBA_BGR: return FontRenderParams::SUBPIXEL_RENDERING_BGR;
89 case FC_RGBA_VRGB: return FontRenderParams::SUBPIXEL_RENDERING_VRGB;
90 case FC_RGBA_VBGR: return FontRenderParams::SUBPIXEL_RENDERING_VBGR;
91 default: return FontRenderParams::SUBPIXEL_RENDERING_NONE;
95 // Queries Fontconfig for rendering settings and updates |params_out| and
96 // |family_out| (if non-NULL). Returns false on failure.
97 bool QueryFontconfig(const FontRenderParamsQuery& query,
98 FontRenderParams* params_out,
99 std::string* family_out) {
100 struct FcPatternDeleter {
101 void operator()(FcPattern* ptr) const { FcPatternDestroy(ptr); }
103 typedef scoped_ptr<FcPattern, FcPatternDeleter> ScopedFcPattern;
105 ScopedFcPattern query_pattern(FcPatternCreate());
106 CHECK(query_pattern);
108 FcPatternAddBool(query_pattern.get(), FC_SCALABLE, FcTrue);
110 for (std::vector<std::string>::const_iterator it = query.families.begin();
111 it != query.families.end(); ++it) {
112 FcPatternAddString(query_pattern.get(),
113 FC_FAMILY, reinterpret_cast<const FcChar8*>(it->c_str()));
115 if (query.pixel_size > 0)
116 FcPatternAddDouble(query_pattern.get(), FC_PIXEL_SIZE, query.pixel_size);
117 if (query.point_size > 0)
118 FcPatternAddInteger(query_pattern.get(), FC_SIZE, query.point_size);
119 if (query.style >= 0) {
120 FcPatternAddInteger(query_pattern.get(), FC_SLANT,
121 (query.style & Font::ITALIC) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN);
122 FcPatternAddInteger(query_pattern.get(), FC_WEIGHT,
123 (query.style & Font::BOLD) ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL);
126 FcConfigSubstitute(NULL, query_pattern.get(), FcMatchPattern);
127 FcDefaultSubstitute(query_pattern.get());
129 ScopedFcPattern result_pattern;
130 if (query.is_empty()) {
131 // If the query was empty, call FcConfigSubstituteWithPat() to get
132 // non-family-specific configuration so it can be used as the default.
133 result_pattern.reset(FcPatternDuplicate(query_pattern.get()));
134 if (!result_pattern)
135 return false;
136 FcPatternDel(result_pattern.get(), FC_FAMILY);
137 FcConfigSubstituteWithPat(NULL, result_pattern.get(), query_pattern.get(),
138 FcMatchFont);
139 } else {
140 FcResult result;
141 result_pattern.reset(FcFontMatch(NULL, query_pattern.get(), &result));
142 if (!result_pattern)
143 return false;
145 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));
154 if (params_out) {
155 FcBool fc_antialias = 0;
156 if (FcPatternGetBool(result_pattern.get(), FC_ANTIALIAS, 0,
157 &fc_antialias) == FcResultMatch) {
158 params_out->antialiasing = fc_antialias;
161 FcBool fc_autohint = 0;
162 if (FcPatternGetBool(result_pattern.get(), FC_AUTOHINT, 0, &fc_autohint) ==
163 FcResultMatch) {
164 params_out->autohinter = fc_autohint;
167 FcBool fc_bitmap = 0;
168 if (FcPatternGetBool(result_pattern.get(), FC_EMBEDDED_BITMAP, 0,
169 &fc_bitmap) ==
170 FcResultMatch) {
171 params_out->use_bitmaps = fc_bitmap;
174 FcBool fc_hinting = 0;
175 if (FcPatternGetBool(result_pattern.get(), FC_HINTING, 0, &fc_hinting) ==
176 FcResultMatch) {
177 int fc_hint_style = FC_HINT_NONE;
178 if (fc_hinting) {
179 FcPatternGetInteger(
180 result_pattern.get(), FC_HINT_STYLE, 0, &fc_hint_style);
182 params_out->hinting = ConvertFontconfigHintStyle(fc_hint_style);
185 int fc_rgba = FC_RGBA_NONE;
186 if (FcPatternGetInteger(result_pattern.get(), FC_RGBA, 0, &fc_rgba) ==
187 FcResultMatch)
188 params_out->subpixel_rendering = ConvertFontconfigRgba(fc_rgba);
191 return true;
194 // Serialize |query| into a string and hash it to a value suitable for use as a
195 // cache key.
196 uint32 HashFontRenderParamsQuery(const FontRenderParamsQuery& query) {
197 return base::Hash(base::StringPrintf(
198 "%d|%d|%d|%d|%s|%f", query.for_web_contents, query.pixel_size,
199 query.point_size, query.style, JoinString(query.families, ',').c_str(),
200 query.device_scale_factor));
203 } // namespace
205 FontRenderParams GetFontRenderParams(const FontRenderParamsQuery& query,
206 std::string* family_out) {
207 FontRenderParamsQuery actual_query(query);
208 #if defined(OS_CHROMEOS)
209 if (actual_query.device_scale_factor == 0)
210 actual_query.device_scale_factor = device_scale_factor_for_internal_display;
211 #endif
212 const uint32 hash = HashFontRenderParamsQuery(actual_query);
213 SynchronizedCache* synchronized_cache = g_synchronized_cache.Pointer();
216 // Try to find a cached result so Fontconfig doesn't need to be queried.
217 base::AutoLock lock(synchronized_cache->lock);
218 Cache::const_iterator it = synchronized_cache->cache.Get(hash);
219 if (it != synchronized_cache->cache.end()) {
220 DVLOG(1) << "Returning cached params for " << hash;
221 const QueryResult& result = it->second;
222 if (family_out)
223 *family_out = result.family;
224 return result.params;
228 DVLOG(1) << "Computing params for " << hash;
229 if (family_out)
230 family_out->clear();
232 // Start with the delegate's settings, but let Fontconfig have the final say.
233 FontRenderParams params;
234 const LinuxFontDelegate* delegate = LinuxFontDelegate::instance();
235 if (delegate)
236 params = delegate->GetDefaultFontRenderParams();
237 QueryFontconfig(actual_query, &params, family_out);
238 if (!params.antialiasing) {
239 // Cairo forces full hinting when antialiasing is disabled, since anything
240 // less than that looks awful; do the same here. Requesting subpixel
241 // rendering or positioning doesn't make sense either.
242 params.hinting = FontRenderParams::HINTING_FULL;
243 params.subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_NONE;
244 params.subpixel_positioning = false;
245 } else {
246 // Fontconfig doesn't support configuring subpixel positioning; check a
247 // flag.
248 params.subpixel_positioning =
249 actual_query.for_web_contents
250 ? base::CommandLine::ForCurrentProcess()->HasSwitch(
251 switches::kEnableWebkitTextSubpixelPositioning)
252 : IsBrowserTextSubpixelPositioningEnabled(actual_query);
254 // To enable subpixel positioning, we need to disable hinting.
255 if (params.subpixel_positioning)
256 params.hinting = FontRenderParams::HINTING_NONE;
259 // Use the first family from the list if Fontconfig didn't suggest a family.
260 if (family_out && family_out->empty() && !actual_query.families.empty())
261 *family_out = actual_query.families[0];
264 // Store the result. It's fine if this overwrites a result that was cached
265 // by a different thread in the meantime; the values should be identical.
266 base::AutoLock lock(synchronized_cache->lock);
267 synchronized_cache->cache.Put(hash,
268 QueryResult(params, family_out ? *family_out : std::string()));
271 return params;
274 void ClearFontRenderParamsCacheForTest() {
275 SynchronizedCache* synchronized_cache = g_synchronized_cache.Pointer();
276 base::AutoLock lock(synchronized_cache->lock);
277 synchronized_cache->cache.Clear();
280 #if defined(OS_CHROMEOS)
281 float GetFontRenderParamsDeviceScaleFactor() {
282 return device_scale_factor_for_internal_display;
285 void SetFontRenderParamsDeviceScaleFactor(float device_scale_factor) {
286 device_scale_factor_for_internal_display = device_scale_factor;
288 #endif
290 } // namespace gfx