1 // Copyright 2014 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 "base/files/file_path.h" 8 #include "base/files/scoped_temp_dir.h" 9 #include "base/logging.h" 10 #include "base/macros.h" 11 #include "testing/gtest/include/gtest/gtest.h" 12 #include "ui/gfx/font.h" 13 #include "ui/gfx/linux_font_delegate.h" 14 #include "ui/gfx/pango_util.h" 15 #include "ui/gfx/test/fontconfig_util_linux.h" 16 17 namespace gfx { 18 19 namespace { 20 21 // Implementation of LinuxFontDelegate that returns a canned FontRenderParams 22 // struct. This is used to isolate tests from the system's local configuration. 23 class TestFontDelegate : public LinuxFontDelegate { 24 public: 25 TestFontDelegate() {} 26 virtual ~TestFontDelegate() {} 27 28 void set_params(const FontRenderParams& params) { params_ = params; } 29 30 virtual FontRenderParams GetDefaultFontRenderParams() const OVERRIDE { 31 return params_; 32 } 33 virtual scoped_ptr<ScopedPangoFontDescription> 34 GetDefaultPangoFontDescription() const OVERRIDE { 35 NOTIMPLEMENTED(); 36 return scoped_ptr<ScopedPangoFontDescription>(); 37 } 38 virtual double GetFontDPI() const OVERRIDE { 39 NOTIMPLEMENTED(); 40 return 96.0; 41 } 42 43 private: 44 FontRenderParams params_; 45 46 DISALLOW_COPY_AND_ASSIGN(TestFontDelegate); 47 }; 48 49 // Loads the first system font defined by fontconfig_util_linux.h with a base 50 // filename of |basename|. Case is ignored. 51 bool LoadSystemFont(const std::string& basename) { 52 for (size_t i = 0; i < kNumSystemFontsForFontconfig; ++i) { 53 base::FilePath path(gfx::kSystemFontsForFontconfig[i]); 54 if (strcasecmp(path.BaseName().value().c_str(), basename.c_str()) == 0) 55 return LoadFontIntoFontconfig(path); 56 } 57 LOG(ERROR) << "Unable to find system font named " << basename; 58 return false; 59 } 60 61 } // namespace 62 63 class FontRenderParamsTest : public testing::Test { 64 public: 65 FontRenderParamsTest() { 66 SetUpFontconfig(); 67 CHECK(temp_dir_.CreateUniqueTempDir()); 68 original_font_delegate_ = LinuxFontDelegate::instance(); 69 LinuxFontDelegate::SetInstance(&test_font_delegate_); 70 ClearFontRenderParamsCacheForTest(); 71 } 72 73 virtual ~FontRenderParamsTest() { 74 LinuxFontDelegate::SetInstance( 75 const_cast<LinuxFontDelegate*>(original_font_delegate_)); 76 TearDownFontconfig(); 77 } 78 79 protected: 80 base::ScopedTempDir temp_dir_; 81 const LinuxFontDelegate* original_font_delegate_; 82 TestFontDelegate test_font_delegate_; 83 84 private: 85 DISALLOW_COPY_AND_ASSIGN(FontRenderParamsTest); 86 }; 87 88 TEST_F(FontRenderParamsTest, Default) { 89 // Fontconfig needs to know about at least one font to return a match. 90 ASSERT_TRUE(LoadSystemFont("arial.ttf")); 91 ASSERT_TRUE(LoadConfigDataIntoFontconfig(temp_dir_.path(), 92 std::string(kFontconfigFileHeader) + 93 kFontconfigMatchHeader + 94 CreateFontconfigEditStanza("antialias", "bool", "true") + 95 CreateFontconfigEditStanza("autohint", "bool", "false") + 96 CreateFontconfigEditStanza("hinting", "bool", "true") + 97 CreateFontconfigEditStanza("hintstyle", "const", "hintfull") + 98 CreateFontconfigEditStanza("rgba", "const", "rgb") + 99 kFontconfigMatchFooter + 100 kFontconfigFileFooter)); 101 102 FontRenderParams params = GetFontRenderParams( 103 FontRenderParamsQuery(true), NULL); 104 EXPECT_TRUE(params.antialiasing); 105 EXPECT_FALSE(params.autohinter); 106 EXPECT_TRUE(params.use_bitmaps); 107 EXPECT_EQ(FontRenderParams::HINTING_FULL, params.hinting); 108 EXPECT_FALSE(params.subpixel_positioning); 109 EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_RGB, 110 params.subpixel_rendering); 111 } 112 113 TEST_F(FontRenderParamsTest, Size) { 114 ASSERT_TRUE(LoadSystemFont("arial.ttf")); 115 ASSERT_TRUE(LoadConfigDataIntoFontconfig(temp_dir_.path(), 116 std::string(kFontconfigFileHeader) + 117 kFontconfigMatchHeader + 118 CreateFontconfigEditStanza("antialias", "bool", "true") + 119 CreateFontconfigEditStanza("hinting", "bool", "true") + 120 CreateFontconfigEditStanza("hintstyle", "const", "hintfull") + 121 CreateFontconfigEditStanza("rgba", "const", "none") + 122 kFontconfigMatchFooter + 123 kFontconfigMatchHeader + 124 CreateFontconfigTestStanza("pixelsize", "less_eq", "double", "10") + 125 CreateFontconfigEditStanza("antialias", "bool", "false") + 126 kFontconfigMatchFooter + 127 kFontconfigMatchHeader + 128 CreateFontconfigTestStanza("size", "more_eq", "double", "20") + 129 CreateFontconfigEditStanza("hintstyle", "const", "hintslight") + 130 CreateFontconfigEditStanza("rgba", "const", "rgb") + 131 kFontconfigMatchFooter + 132 kFontconfigFileFooter)); 133 134 // The defaults should be used when the supplied size isn't matched by the 135 // second or third blocks. 136 FontRenderParamsQuery query(false); 137 query.pixel_size = 12; 138 FontRenderParams params = GetFontRenderParams(query, NULL); 139 EXPECT_TRUE(params.antialiasing); 140 EXPECT_EQ(FontRenderParams::HINTING_FULL, params.hinting); 141 EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_NONE, 142 params.subpixel_rendering); 143 144 query.pixel_size = 10; 145 params = GetFontRenderParams(query, NULL); 146 EXPECT_FALSE(params.antialiasing); 147 EXPECT_EQ(FontRenderParams::HINTING_FULL, params.hinting); 148 EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_NONE, 149 params.subpixel_rendering); 150 151 query.pixel_size = 0; 152 query.point_size = 20; 153 params = GetFontRenderParams(query, NULL); 154 EXPECT_TRUE(params.antialiasing); 155 EXPECT_EQ(FontRenderParams::HINTING_SLIGHT, params.hinting); 156 EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_RGB, 157 params.subpixel_rendering); 158 } 159 160 TEST_F(FontRenderParamsTest, Style) { 161 ASSERT_TRUE(LoadSystemFont("arial.ttf")); 162 // Load a config that disables subpixel rendering for bold text and disables 163 // hinting for italic text. 164 ASSERT_TRUE(LoadConfigDataIntoFontconfig(temp_dir_.path(), 165 std::string(kFontconfigFileHeader) + 166 kFontconfigMatchHeader + 167 CreateFontconfigEditStanza("antialias", "bool", "true") + 168 CreateFontconfigEditStanza("hinting", "bool", "true") + 169 CreateFontconfigEditStanza("hintstyle", "const", "hintslight") + 170 CreateFontconfigEditStanza("rgba", "const", "rgb") + 171 kFontconfigMatchFooter + 172 kFontconfigMatchHeader + 173 CreateFontconfigTestStanza("weight", "eq", "const", "bold") + 174 CreateFontconfigEditStanza("rgba", "const", "none") + 175 kFontconfigMatchFooter + 176 kFontconfigMatchHeader + 177 CreateFontconfigTestStanza("slant", "eq", "const", "italic") + 178 CreateFontconfigEditStanza("hinting", "bool", "false") + 179 kFontconfigMatchFooter + 180 kFontconfigFileFooter)); 181 182 FontRenderParamsQuery query(false); 183 query.style = Font::NORMAL; 184 FontRenderParams params = GetFontRenderParams(query, NULL); 185 EXPECT_EQ(FontRenderParams::HINTING_SLIGHT, params.hinting); 186 EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_RGB, 187 params.subpixel_rendering); 188 189 query.style = Font::BOLD; 190 params = GetFontRenderParams(query, NULL); 191 EXPECT_EQ(FontRenderParams::HINTING_SLIGHT, params.hinting); 192 EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_NONE, 193 params.subpixel_rendering); 194 195 query.style = Font::ITALIC; 196 params = GetFontRenderParams(query, NULL); 197 EXPECT_EQ(FontRenderParams::HINTING_NONE, params.hinting); 198 EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_RGB, 199 params.subpixel_rendering); 200 201 query.style = Font::BOLD | Font::ITALIC; 202 params = GetFontRenderParams(query, NULL); 203 EXPECT_EQ(FontRenderParams::HINTING_NONE, params.hinting); 204 EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_NONE, 205 params.subpixel_rendering); 206 } 207 208 TEST_F(FontRenderParamsTest, Scalable) { 209 ASSERT_TRUE(LoadSystemFont("arial.ttf")); 210 // Load a config that only enables antialiasing for scalable fonts. 211 ASSERT_TRUE(LoadConfigDataIntoFontconfig(temp_dir_.path(), 212 std::string(kFontconfigFileHeader) + 213 kFontconfigMatchHeader + 214 CreateFontconfigEditStanza("antialias", "bool", "false") + 215 kFontconfigMatchFooter + 216 kFontconfigMatchHeader + 217 CreateFontconfigTestStanza("scalable", "eq", "bool", "true") + 218 CreateFontconfigEditStanza("antialias", "bool", "true") + 219 kFontconfigMatchFooter + 220 kFontconfigFileFooter)); 221 222 // Check that we specifically ask how scalable fonts should be rendered. 223 FontRenderParams params = GetFontRenderParams( 224 FontRenderParamsQuery(false), NULL); 225 EXPECT_TRUE(params.antialiasing); 226 } 227 228 TEST_F(FontRenderParamsTest, UseBitmaps) { 229 ASSERT_TRUE(LoadSystemFont("arial.ttf")); 230 // Load a config that enables embedded bitmaps for fonts <= 10 pixels. 231 ASSERT_TRUE(LoadConfigDataIntoFontconfig(temp_dir_.path(), 232 std::string(kFontconfigFileHeader) + 233 kFontconfigMatchHeader + 234 CreateFontconfigEditStanza("embeddedbitmap", "bool", "false") + 235 kFontconfigMatchFooter + 236 kFontconfigMatchHeader + 237 CreateFontconfigTestStanza("pixelsize", "less_eq", "double", "10") + 238 CreateFontconfigEditStanza("embeddedbitmap", "bool", "true") + 239 kFontconfigMatchFooter + 240 kFontconfigFileFooter)); 241 242 FontRenderParamsQuery query(false); 243 FontRenderParams params = GetFontRenderParams(query, NULL); 244 EXPECT_FALSE(params.use_bitmaps); 245 246 query.pixel_size = 5; 247 params = GetFontRenderParams(query, NULL); 248 EXPECT_TRUE(params.use_bitmaps); 249 } 250 251 TEST_F(FontRenderParamsTest, ForceFullHintingWhenAntialiasingIsDisabled) { 252 // Load a config that disables antialiasing and hinting while requesting 253 // subpixel rendering. 254 ASSERT_TRUE(LoadSystemFont("arial.ttf")); 255 ASSERT_TRUE(LoadConfigDataIntoFontconfig(temp_dir_.path(), 256 std::string(kFontconfigFileHeader) + 257 kFontconfigMatchHeader + 258 CreateFontconfigEditStanza("antialias", "bool", "false") + 259 CreateFontconfigEditStanza("hinting", "bool", "false") + 260 CreateFontconfigEditStanza("hintstyle", "const", "hintnone") + 261 CreateFontconfigEditStanza("rgba", "const", "rgb") + 262 kFontconfigMatchFooter + 263 kFontconfigFileFooter)); 264 265 // Full hinting should be forced. See the comment in GetFontRenderParams() for 266 // more information. 267 FontRenderParams params = GetFontRenderParams( 268 FontRenderParamsQuery(false), NULL); 269 EXPECT_FALSE(params.antialiasing); 270 EXPECT_EQ(FontRenderParams::HINTING_FULL, params.hinting); 271 EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_NONE, 272 params.subpixel_rendering); 273 EXPECT_FALSE(params.subpixel_positioning); 274 } 275 276 #if defined(OS_CHROMEOS) 277 TEST_F(FontRenderParamsTest, ForceSubpixelPositioning) { 278 { 279 FontRenderParams params = 280 GetFontRenderParams(FontRenderParamsQuery(false), NULL); 281 EXPECT_TRUE(params.antialiasing); 282 EXPECT_FALSE(params.subpixel_positioning); 283 SetFontRenderParamsDeviceScaleFactor(1.0f); 284 } 285 ClearFontRenderParamsCacheForTest(); 286 SetFontRenderParamsDeviceScaleFactor(1.25f); 287 // Subpixel positioning should be forced. 288 { 289 FontRenderParams params = 290 GetFontRenderParams(FontRenderParamsQuery(false), NULL); 291 EXPECT_TRUE(params.antialiasing); 292 EXPECT_TRUE(params.subpixel_positioning); 293 SetFontRenderParamsDeviceScaleFactor(1.0f); 294 } 295 } 296 #endif 297 298 TEST_F(FontRenderParamsTest, OnlySetConfiguredValues) { 299 // Configure the LinuxFontDelegate (which queries GtkSettings on desktop 300 // Linux) to request subpixel rendering. 301 FontRenderParams system_params; 302 system_params.subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_RGB; 303 test_font_delegate_.set_params(system_params); 304 305 // Load a Fontconfig config that enables antialiasing but doesn't say anything 306 // about subpixel rendering. 307 ASSERT_TRUE(LoadSystemFont("arial.ttf")); 308 ASSERT_TRUE(LoadConfigDataIntoFontconfig(temp_dir_.path(), 309 std::string(kFontconfigFileHeader) + 310 kFontconfigMatchHeader + 311 CreateFontconfigEditStanza("antialias", "bool", "true") + 312 kFontconfigMatchFooter + 313 kFontconfigFileFooter)); 314 315 // The subpixel rendering setting from the delegate should make it through. 316 FontRenderParams params = GetFontRenderParams( 317 FontRenderParamsQuery(false), NULL); 318 EXPECT_EQ(system_params.subpixel_rendering, params.subpixel_rendering); 319 } 320 321 TEST_F(FontRenderParamsTest, NoFontconfigMatch) { 322 // Don't load a Fontconfig configuration. 323 FontRenderParams system_params; 324 system_params.antialiasing = true; 325 system_params.hinting = FontRenderParams::HINTING_MEDIUM; 326 system_params.subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_RGB; 327 test_font_delegate_.set_params(system_params); 328 329 FontRenderParamsQuery query(false); 330 query.families.push_back("Arial"); 331 query.families.push_back("Times New Roman"); 332 query.pixel_size = 10; 333 std::string suggested_family; 334 FontRenderParams params = GetFontRenderParams(query, &suggested_family); 335 336 // The system params and the first requested family should be returned. 337 EXPECT_EQ(system_params.antialiasing, params.antialiasing); 338 EXPECT_EQ(system_params.hinting, params.hinting); 339 EXPECT_EQ(system_params.subpixel_rendering, params.subpixel_rendering); 340 EXPECT_EQ(query.families[0], suggested_family); 341 } 342 343 TEST_F(FontRenderParamsTest, MissingFamily) { 344 // With Arial and Verdana installed, request (in order) Helvetica, Arial, and 345 // Verdana and check that Arial is returned. 346 ASSERT_TRUE(LoadSystemFont("arial.ttf")); 347 ASSERT_TRUE(LoadSystemFont("verdana.ttf")); 348 FontRenderParamsQuery query(false); 349 query.families.push_back("Helvetica"); 350 query.families.push_back("Arial"); 351 query.families.push_back("Verdana"); 352 std::string suggested_family; 353 GetFontRenderParams(query, &suggested_family); 354 EXPECT_EQ("Arial", suggested_family); 355 } 356 357 TEST_F(FontRenderParamsTest, SubstituteFamily) { 358 // Configure Fontconfig to use Verdana for both Helvetica and Arial. 359 ASSERT_TRUE(LoadSystemFont("arial.ttf")); 360 ASSERT_TRUE(LoadSystemFont("verdana.ttf")); 361 ASSERT_TRUE(LoadConfigDataIntoFontconfig(temp_dir_.path(), 362 std::string(kFontconfigFileHeader) + 363 CreateFontconfigAliasStanza("Helvetica", "Verdana") + 364 kFontconfigMatchHeader + 365 CreateFontconfigTestStanza("family", "eq", "string", "Arial") + 366 CreateFontconfigEditStanza("family", "string", "Verdana") + 367 kFontconfigMatchFooter + 368 kFontconfigFileFooter)); 369 370 FontRenderParamsQuery query(false); 371 query.families.push_back("Helvetica"); 372 std::string suggested_family; 373 GetFontRenderParams(query, &suggested_family); 374 EXPECT_EQ("Verdana", suggested_family); 375 376 query.families.clear(); 377 query.families.push_back("Arial"); 378 suggested_family.clear(); 379 GetFontRenderParams(query, &suggested_family); 380 EXPECT_EQ("Verdana", suggested_family); 381 } 382 383 } // namespace gfx 384