| OLD | NEW |
| (Empty) |
| 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 | |
| 5 #include "ui/gfx/font_render_params.h" | |
| 6 | |
| 7 #include <fontconfig/fontconfig.h> | |
| 8 | |
| 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/strings/string_util.h" | |
| 16 #include "base/strings/stringprintf.h" | |
| 17 #include "base/synchronization/lock.h" | |
| 18 #include "ui/gfx/font.h" | |
| 19 #include "ui/gfx/linux_font_delegate.h" | |
| 20 #include "ui/gfx/switches.h" | |
| 21 | |
| 22 namespace gfx { | |
| 23 | |
| 24 namespace { | |
| 25 | |
| 26 #if defined(OS_CHROMEOS) | |
| 27 // A device scale factor for an internal display (if any) | |
| 28 // that is used to determine if subpixel positioning should be used. | |
| 29 float device_scale_factor_for_internal_display = 1.0f; | |
| 30 #endif | |
| 31 | |
| 32 // Number of recent GetFontRenderParams() results to cache. | |
| 33 const size_t kCacheSize = 20; | |
| 34 | |
| 35 // Cached result from a call to GetFontRenderParams(). | |
| 36 struct QueryResult { | |
| 37 QueryResult(const FontRenderParams& params, const std::string& family) | |
| 38 : params(params), | |
| 39 family(family) { | |
| 40 } | |
| 41 ~QueryResult() {} | |
| 42 | |
| 43 FontRenderParams params; | |
| 44 std::string family; | |
| 45 }; | |
| 46 | |
| 47 // Keyed by hashes of FontRenderParamQuery structs from | |
| 48 // HashFontRenderParamsQuery(). | |
| 49 typedef base::MRUCache<uint32, QueryResult> Cache; | |
| 50 | |
| 51 // A cache and the lock that must be held while accessing it. | |
| 52 // GetFontRenderParams() is called by both the UI thread and the sandbox IPC | |
| 53 // thread. | |
| 54 struct SynchronizedCache { | |
| 55 SynchronizedCache() : cache(kCacheSize) {} | |
| 56 | |
| 57 base::Lock lock; | |
| 58 Cache cache; | |
| 59 }; | |
| 60 | |
| 61 base::LazyInstance<SynchronizedCache>::Leaky g_synchronized_cache = | |
| 62 LAZY_INSTANCE_INITIALIZER; | |
| 63 | |
| 64 bool IsBrowserTextSubpixelPositioningEnabled() { | |
| 65 #if defined(OS_CHROMEOS) | |
| 66 return device_scale_factor_for_internal_display > 1.0f; | |
| 67 #else | |
| 68 return false; | |
| 69 #endif | |
| 70 } | |
| 71 | |
| 72 // Converts Fontconfig FC_HINT_STYLE to FontRenderParams::Hinting. | |
| 73 FontRenderParams::Hinting ConvertFontconfigHintStyle(int hint_style) { | |
| 74 switch (hint_style) { | |
| 75 case FC_HINT_SLIGHT: return FontRenderParams::HINTING_SLIGHT; | |
| 76 case FC_HINT_MEDIUM: return FontRenderParams::HINTING_MEDIUM; | |
| 77 case FC_HINT_FULL: return FontRenderParams::HINTING_FULL; | |
| 78 default: return FontRenderParams::HINTING_NONE; | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 // Converts Fontconfig FC_RGBA to FontRenderParams::SubpixelRendering. | |
| 83 FontRenderParams::SubpixelRendering ConvertFontconfigRgba(int rgba) { | |
| 84 switch (rgba) { | |
| 85 case FC_RGBA_RGB: return FontRenderParams::SUBPIXEL_RENDERING_RGB; | |
| 86 case FC_RGBA_BGR: return FontRenderParams::SUBPIXEL_RENDERING_BGR; | |
| 87 case FC_RGBA_VRGB: return FontRenderParams::SUBPIXEL_RENDERING_VRGB; | |
| 88 case FC_RGBA_VBGR: return FontRenderParams::SUBPIXEL_RENDERING_VBGR; | |
| 89 default: return FontRenderParams::SUBPIXEL_RENDERING_NONE; | |
| 90 } | |
| 91 } | |
| 92 | |
| 93 // Queries Fontconfig for rendering settings and updates |params_out| and | |
| 94 // |family_out| (if non-NULL). Returns false on failure. | |
| 95 bool QueryFontconfig(const FontRenderParamsQuery& query, | |
| 96 FontRenderParams* params_out, | |
| 97 std::string* family_out) { | |
| 98 FcPattern* pattern = FcPatternCreate(); | |
| 99 CHECK(pattern); | |
| 100 | |
| 101 FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); | |
| 102 | |
| 103 for (std::vector<std::string>::const_iterator it = query.families.begin(); | |
| 104 it != query.families.end(); ++it) { | |
| 105 FcPatternAddString( | |
| 106 pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(it->c_str())); | |
| 107 } | |
| 108 if (query.pixel_size > 0) | |
| 109 FcPatternAddDouble(pattern, FC_PIXEL_SIZE, query.pixel_size); | |
| 110 if (query.point_size > 0) | |
| 111 FcPatternAddInteger(pattern, FC_SIZE, query.point_size); | |
| 112 if (query.style >= 0) { | |
| 113 FcPatternAddInteger(pattern, FC_SLANT, | |
| 114 (query.style & Font::ITALIC) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN); | |
| 115 FcPatternAddInteger(pattern, FC_WEIGHT, | |
| 116 (query.style & Font::BOLD) ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL); | |
| 117 } | |
| 118 | |
| 119 FcConfigSubstitute(NULL, pattern, FcMatchPattern); | |
| 120 FcDefaultSubstitute(pattern); | |
| 121 FcResult result; | |
| 122 FcPattern* match = FcFontMatch(NULL, pattern, &result); | |
| 123 FcPatternDestroy(pattern); | |
| 124 if (!match) | |
| 125 return false; | |
| 126 | |
| 127 if (family_out) { | |
| 128 FcChar8* family = NULL; | |
| 129 FcPatternGetString(match, FC_FAMILY, 0, &family); | |
| 130 if (family) | |
| 131 family_out->assign(reinterpret_cast<const char*>(family)); | |
| 132 } | |
| 133 | |
| 134 if (params_out) { | |
| 135 FcBool fc_antialias = 0; | |
| 136 if (FcPatternGetBool(match, FC_ANTIALIAS, 0, &fc_antialias) == | |
| 137 FcResultMatch) { | |
| 138 params_out->antialiasing = fc_antialias; | |
| 139 } | |
| 140 | |
| 141 FcBool fc_autohint = 0; | |
| 142 if (FcPatternGetBool(match, FC_AUTOHINT, 0, &fc_autohint) == | |
| 143 FcResultMatch) { | |
| 144 params_out->autohinter = fc_autohint; | |
| 145 } | |
| 146 | |
| 147 FcBool fc_bitmap = 0; | |
| 148 if (FcPatternGetBool(match, FC_EMBEDDED_BITMAP, 0, &fc_bitmap) == | |
| 149 FcResultMatch) { | |
| 150 params_out->use_bitmaps = fc_bitmap; | |
| 151 } | |
| 152 | |
| 153 FcBool fc_hinting = 0; | |
| 154 if (FcPatternGetBool(match, FC_HINTING, 0, &fc_hinting) == FcResultMatch) { | |
| 155 int fc_hint_style = FC_HINT_NONE; | |
| 156 if (fc_hinting) | |
| 157 FcPatternGetInteger(match, FC_HINT_STYLE, 0, &fc_hint_style); | |
| 158 params_out->hinting = ConvertFontconfigHintStyle(fc_hint_style); | |
| 159 } | |
| 160 | |
| 161 int fc_rgba = FC_RGBA_NONE; | |
| 162 if (FcPatternGetInteger(match, FC_RGBA, 0, &fc_rgba) == FcResultMatch) | |
| 163 params_out->subpixel_rendering = ConvertFontconfigRgba(fc_rgba); | |
| 164 } | |
| 165 | |
| 166 FcPatternDestroy(match); | |
| 167 return true; | |
| 168 } | |
| 169 | |
| 170 // Serialize |query| into a string and hash it to a value suitable for use as a | |
| 171 // cache key. | |
| 172 uint32 HashFontRenderParamsQuery(const FontRenderParamsQuery& query) { | |
| 173 return base::Hash(base::StringPrintf("%d|%d|%d|%d|%s", | |
| 174 query.for_web_contents, query.pixel_size, query.point_size, query.style, | |
| 175 JoinString(query.families, ',').c_str())); | |
| 176 } | |
| 177 | |
| 178 } // namespace | |
| 179 | |
| 180 FontRenderParams GetFontRenderParams(const FontRenderParamsQuery& query, | |
| 181 std::string* family_out) { | |
| 182 const uint32 hash = HashFontRenderParamsQuery(query); | |
| 183 SynchronizedCache* synchronized_cache = g_synchronized_cache.Pointer(); | |
| 184 | |
| 185 { | |
| 186 // Try to find a cached result so Fontconfig doesn't need to be queried. | |
| 187 base::AutoLock lock(synchronized_cache->lock); | |
| 188 Cache::const_iterator it = synchronized_cache->cache.Get(hash); | |
| 189 if (it != synchronized_cache->cache.end()) { | |
| 190 DVLOG(1) << "Returning cached params for " << hash; | |
| 191 const QueryResult& result = it->second; | |
| 192 if (family_out) | |
| 193 *family_out = result.family; | |
| 194 return result.params; | |
| 195 } | |
| 196 } | |
| 197 | |
| 198 DVLOG(1) << "Computing params for " << hash; | |
| 199 if (family_out) | |
| 200 family_out->clear(); | |
| 201 | |
| 202 // Start with the delegate's settings, but let Fontconfig have the final say. | |
| 203 FontRenderParams params; | |
| 204 const LinuxFontDelegate* delegate = LinuxFontDelegate::instance(); | |
| 205 if (delegate) | |
| 206 params = delegate->GetDefaultFontRenderParams(); | |
| 207 QueryFontconfig(query, ¶ms, family_out); | |
| 208 if (!params.antialiasing) { | |
| 209 // Cairo forces full hinting when antialiasing is disabled, since anything | |
| 210 // less than that looks awful; do the same here. Requesting subpixel | |
| 211 // rendering or positioning doesn't make sense either. | |
| 212 params.hinting = FontRenderParams::HINTING_FULL; | |
| 213 params.subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_NONE; | |
| 214 params.subpixel_positioning = false; | |
| 215 } else { | |
| 216 // Fontconfig doesn't support configuring subpixel positioning; check a | |
| 217 // flag. | |
| 218 params.subpixel_positioning = | |
| 219 query.for_web_contents ? | |
| 220 base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 221 switches::kEnableWebkitTextSubpixelPositioning) : | |
| 222 IsBrowserTextSubpixelPositioningEnabled(); | |
| 223 | |
| 224 // To enable subpixel positioning, we need to disable hinting. | |
| 225 if (params.subpixel_positioning) | |
| 226 params.hinting = FontRenderParams::HINTING_NONE; | |
| 227 } | |
| 228 | |
| 229 // Use the first family from the list if Fontconfig didn't suggest a family. | |
| 230 if (family_out && family_out->empty() && !query.families.empty()) | |
| 231 *family_out = query.families[0]; | |
| 232 | |
| 233 { | |
| 234 // Store the result. It's fine if this overwrites a result that was cached | |
| 235 // by a different thread in the meantime; the values should be identical. | |
| 236 base::AutoLock lock(synchronized_cache->lock); | |
| 237 synchronized_cache->cache.Put(hash, | |
| 238 QueryResult(params, family_out ? *family_out : std::string())); | |
| 239 } | |
| 240 | |
| 241 return params; | |
| 242 } | |
| 243 | |
| 244 void ClearFontRenderParamsCacheForTest() { | |
| 245 SynchronizedCache* synchronized_cache = g_synchronized_cache.Pointer(); | |
| 246 base::AutoLock lock(synchronized_cache->lock); | |
| 247 synchronized_cache->cache.Clear(); | |
| 248 } | |
| 249 | |
| 250 #if defined(OS_CHROMEOS) | |
| 251 void SetFontRenderParamsDeviceScaleFactor(float device_scale_factor) { | |
| 252 device_scale_factor_for_internal_display = device_scale_factor; | |
| 253 } | |
| 254 #endif | |
| 255 | |
| 256 } // namespace gfx | |
| OLD | NEW |