cc: Add more eviction categories to picture layer impl.
[chromium-blink-merge.git] / ui / gfx / font_render_params_linux.cc
blobf02636e8050c2da9466648995aada7952e1f09f6
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 "base/command_line.h"
8 #include "base/containers/mru_cache.h"
9 #include "base/hash.h"
10 #include "base/lazy_instance.h"
11 #include "base/logging.h"
12 #include "base/macros.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/synchronization/lock.h"
16 #include "ui/gfx/font.h"
17 #include "ui/gfx/linux_font_delegate.h"
18 #include "ui/gfx/switches.h"
20 #include <fontconfig/fontconfig.h>
22 namespace gfx {
24 namespace {
26 // Keyed by hashes of FontRenderParamQuery structs from
27 // HashFontRenderParamsQuery().
28 typedef base::MRUCache<uint32, FontRenderParams> Cache;
30 // Number of recent GetFontRenderParams() results to cache.
31 const size_t kCacheSize = 20;
33 // A cache and the lock that must be held while accessing it.
34 // GetFontRenderParams() is called by both the UI thread and the sandbox IPC
35 // thread.
36 struct SynchronizedCache {
37 SynchronizedCache() : cache(kCacheSize) {}
39 base::Lock lock;
40 Cache cache;
43 base::LazyInstance<SynchronizedCache>::Leaky g_synchronized_cache =
44 LAZY_INSTANCE_INITIALIZER;
46 // Converts Fontconfig FC_HINT_STYLE to FontRenderParams::Hinting.
47 FontRenderParams::Hinting ConvertFontconfigHintStyle(int hint_style) {
48 switch (hint_style) {
49 case FC_HINT_SLIGHT: return FontRenderParams::HINTING_SLIGHT;
50 case FC_HINT_MEDIUM: return FontRenderParams::HINTING_MEDIUM;
51 case FC_HINT_FULL: return FontRenderParams::HINTING_FULL;
52 default: return FontRenderParams::HINTING_NONE;
56 // Converts Fontconfig FC_RGBA to FontRenderParams::SubpixelRendering.
57 FontRenderParams::SubpixelRendering ConvertFontconfigRgba(int rgba) {
58 switch (rgba) {
59 case FC_RGBA_RGB: return FontRenderParams::SUBPIXEL_RENDERING_RGB;
60 case FC_RGBA_BGR: return FontRenderParams::SUBPIXEL_RENDERING_BGR;
61 case FC_RGBA_VRGB: return FontRenderParams::SUBPIXEL_RENDERING_VRGB;
62 case FC_RGBA_VBGR: return FontRenderParams::SUBPIXEL_RENDERING_VBGR;
63 default: return FontRenderParams::SUBPIXEL_RENDERING_NONE;
67 // Queries Fontconfig for rendering settings and updates |params_out| and
68 // |family_out| (if non-NULL). Returns false on failure.
69 bool QueryFontconfig(const FontRenderParamsQuery& query,
70 FontRenderParams* params_out,
71 std::string* family_out) {
72 FcPattern* pattern = FcPatternCreate();
73 CHECK(pattern);
75 FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
77 for (std::vector<std::string>::const_iterator it = query.families.begin();
78 it != query.families.end(); ++it) {
79 FcPatternAddString(
80 pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(it->c_str()));
82 if (query.pixel_size > 0)
83 FcPatternAddDouble(pattern, FC_PIXEL_SIZE, query.pixel_size);
84 if (query.point_size > 0)
85 FcPatternAddInteger(pattern, FC_SIZE, query.point_size);
86 if (query.style >= 0) {
87 FcPatternAddInteger(pattern, FC_SLANT,
88 (query.style & Font::ITALIC) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN);
89 FcPatternAddInteger(pattern, FC_WEIGHT,
90 (query.style & Font::BOLD) ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL);
93 FcConfigSubstitute(NULL, pattern, FcMatchPattern);
94 FcDefaultSubstitute(pattern);
95 FcResult result;
96 FcPattern* match = FcFontMatch(NULL, pattern, &result);
97 FcPatternDestroy(pattern);
98 if (!match)
99 return false;
101 if (family_out) {
102 FcChar8* family = NULL;
103 FcPatternGetString(match, FC_FAMILY, 0, &family);
104 if (family)
105 family_out->assign(reinterpret_cast<const char*>(family));
108 if (params_out) {
109 FcBool fc_antialias = 0;
110 if (FcPatternGetBool(match, FC_ANTIALIAS, 0, &fc_antialias) ==
111 FcResultMatch) {
112 params_out->antialiasing = fc_antialias;
115 FcBool fc_autohint = 0;
116 if (FcPatternGetBool(match, FC_AUTOHINT, 0, &fc_autohint) ==
117 FcResultMatch) {
118 params_out->autohinter = fc_autohint;
121 FcBool fc_bitmap = 0;
122 if (FcPatternGetBool(match, FC_EMBEDDED_BITMAP, 0, &fc_bitmap) ==
123 FcResultMatch) {
124 params_out->use_bitmaps = fc_bitmap;
127 FcBool fc_hinting = 0;
128 if (FcPatternGetBool(match, FC_HINTING, 0, &fc_hinting) == FcResultMatch) {
129 int fc_hint_style = FC_HINT_NONE;
130 if (fc_hinting)
131 FcPatternGetInteger(match, FC_HINT_STYLE, 0, &fc_hint_style);
132 params_out->hinting = ConvertFontconfigHintStyle(fc_hint_style);
135 int fc_rgba = FC_RGBA_NONE;
136 if (FcPatternGetInteger(match, FC_RGBA, 0, &fc_rgba) == FcResultMatch)
137 params_out->subpixel_rendering = ConvertFontconfigRgba(fc_rgba);
140 FcPatternDestroy(match);
141 return true;
144 // Serialize |query| into a string and hash it to a value suitable for use as a
145 // cache key.
146 uint32 HashFontRenderParamsQuery(const FontRenderParamsQuery& query) {
147 return base::Hash(base::StringPrintf("%d|%d|%d|%d|%s",
148 query.for_web_contents, query.pixel_size, query.point_size, query.style,
149 JoinString(query.families, ',').c_str()));
152 } // namespace
154 FontRenderParams GetFontRenderParams(const FontRenderParamsQuery& query,
155 std::string* family_out) {
156 const uint32 hash = HashFontRenderParamsQuery(query);
157 if (!family_out) {
158 // The family returned by Fontconfig isn't part of FontRenderParams, so we
159 // can only return a value from the cache if it wasn't requested.
160 SynchronizedCache* synchronized_cache = g_synchronized_cache.Pointer();
161 base::AutoLock lock(synchronized_cache->lock);
162 Cache::const_iterator it = synchronized_cache->cache.Get(hash);
163 if (it != synchronized_cache->cache.end()) {
164 DVLOG(1) << "Returning cached params for " << hash;
165 return it->second;
167 } else {
168 family_out->clear();
170 DVLOG(1) << "Computing params for " << hash
171 << (family_out ? " (family requested)" : "");
173 // Start with the delegate's settings, but let Fontconfig have the final say.
174 FontRenderParams params;
175 const LinuxFontDelegate* delegate = LinuxFontDelegate::instance();
176 if (delegate)
177 params = delegate->GetDefaultFontRenderParams();
178 QueryFontconfig(query, &params, family_out);
180 if (!params.antialiasing) {
181 // Cairo forces full hinting when antialiasing is disabled, since anything
182 // less than that looks awful; do the same here. Requesting subpixel
183 // rendering or positioning doesn't make sense either.
184 params.hinting = FontRenderParams::HINTING_FULL;
185 params.subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_NONE;
186 params.subpixel_positioning = false;
187 } else {
188 // Fontconfig doesn't support configuring subpixel positioning; check a
189 // flag.
190 params.subpixel_positioning = CommandLine::ForCurrentProcess()->HasSwitch(
191 query.for_web_contents ?
192 switches::kEnableWebkitTextSubpixelPositioning :
193 switches::kEnableBrowserTextSubpixelPositioning);
195 // To enable subpixel positioning, we need to disable hinting.
196 if (params.subpixel_positioning)
197 params.hinting = FontRenderParams::HINTING_NONE;
200 // Use the first family from the list if Fontconfig didn't suggest a family.
201 if (family_out && family_out->empty() && !query.families.empty())
202 *family_out = query.families[0];
204 // Store the computed struct. It's fine if this overwrites a struct that was
205 // cached by a different thread in the meantime; the values should be
206 // identical.
207 SynchronizedCache* synchronized_cache = g_synchronized_cache.Pointer();
208 base::AutoLock lock(synchronized_cache->lock);
209 synchronized_cache->cache.Put(hash, params);
211 return params;
214 void ClearFontRenderParamsCacheForTest() {
215 SynchronizedCache* synchronized_cache = g_synchronized_cache.Pointer();
216 base::AutoLock lock(synchronized_cache->lock);
217 synchronized_cache->cache.Clear();
220 } // namespace gfx