Home | History | Annotate | Download | only in gfx
      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