|  | // Copyright 2014 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "ui/gfx/font_render_params.h" | 
|  |  | 
|  | #include "base/files/scoped_temp_dir.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/macros.h" | 
|  | #include "build/build_config.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "ui/gfx/font.h" | 
|  | #include "ui/gfx/linux_font_delegate.h" | 
|  | #include "ui/gfx/test/fontconfig_util_linux.h" | 
|  |  | 
|  | namespace gfx { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Implementation of LinuxFontDelegate that returns a canned FontRenderParams | 
|  | // struct. This is used to isolate tests from the system's local configuration. | 
|  | class TestFontDelegate : public LinuxFontDelegate { | 
|  | public: | 
|  | TestFontDelegate() {} | 
|  | ~TestFontDelegate() override {} | 
|  |  | 
|  | void set_params(const FontRenderParams& params) { params_ = params; } | 
|  |  | 
|  | FontRenderParams GetDefaultFontRenderParams() const override { | 
|  | return params_; | 
|  | } | 
|  | void GetDefaultFontDescription( | 
|  | std::string* family_out, | 
|  | int* size_pixels_out, | 
|  | int* style_out, | 
|  | FontRenderParams* params_out) const override { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | private: | 
|  | FontRenderParams params_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(TestFontDelegate); | 
|  | }; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | class FontRenderParamsTest : public testing::Test { | 
|  | public: | 
|  | FontRenderParamsTest() { | 
|  | SetUpFontconfig(); | 
|  | CHECK(temp_dir_.CreateUniqueTempDir()); | 
|  | original_font_delegate_ = LinuxFontDelegate::instance(); | 
|  | LinuxFontDelegate::SetInstance(&test_font_delegate_); | 
|  | ClearFontRenderParamsCacheForTest(); | 
|  | } | 
|  |  | 
|  | ~FontRenderParamsTest() override { | 
|  | LinuxFontDelegate::SetInstance( | 
|  | const_cast<LinuxFontDelegate*>(original_font_delegate_)); | 
|  | TearDownFontconfig(); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | base::ScopedTempDir temp_dir_; | 
|  | const LinuxFontDelegate* original_font_delegate_; | 
|  | TestFontDelegate test_font_delegate_; | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(FontRenderParamsTest); | 
|  | }; | 
|  |  | 
|  | TEST_F(FontRenderParamsTest, Default) { | 
|  | ASSERT_TRUE(LoadSystemFontIntoFontconfig("arial.ttf")); | 
|  | ASSERT_TRUE(LoadConfigDataIntoFontconfig(temp_dir_.path(), | 
|  | std::string(kFontconfigFileHeader) + | 
|  | // Specify the desired defaults via a font match rather than a pattern | 
|  | // match (since this is the style generally used in /etc/fonts/conf.d). | 
|  | kFontconfigMatchFontHeader + | 
|  | CreateFontconfigEditStanza("antialias", "bool", "true") + | 
|  | CreateFontconfigEditStanza("autohint", "bool", "true") + | 
|  | CreateFontconfigEditStanza("hinting", "bool", "true") + | 
|  | CreateFontconfigEditStanza("hintstyle", "const", "hintslight") + | 
|  | CreateFontconfigEditStanza("rgba", "const", "rgb") + | 
|  | kFontconfigMatchFooter + | 
|  | // Add a font match for Arial. Since it specifies a family, it shouldn't | 
|  | // take effect when querying default settings. | 
|  | kFontconfigMatchFontHeader + | 
|  | CreateFontconfigTestStanza("family", "eq", "string", "Arial") + | 
|  | CreateFontconfigEditStanza("antialias", "bool", "true") + | 
|  | CreateFontconfigEditStanza("autohint", "bool", "false") + | 
|  | CreateFontconfigEditStanza("hinting", "bool", "true") + | 
|  | CreateFontconfigEditStanza("hintstyle", "const", "hintfull") + | 
|  | CreateFontconfigEditStanza("rgba", "const", "none") + | 
|  | kFontconfigMatchFooter + | 
|  | // Add font matches for fonts between 10 and 20 points or pixels. Since | 
|  | // they specify sizes, they also should not affect the defaults. | 
|  | kFontconfigMatchFontHeader + | 
|  | CreateFontconfigTestStanza("size", "more_eq", "double", "10.0") + | 
|  | CreateFontconfigTestStanza("size", "less_eq", "double", "20.0") + | 
|  | CreateFontconfigEditStanza("antialias", "bool", "false") + | 
|  | kFontconfigMatchFooter + | 
|  | kFontconfigMatchFontHeader + | 
|  | CreateFontconfigTestStanza("pixel_size", "more_eq", "double", "10.0") + | 
|  | CreateFontconfigTestStanza("pixel_size", "less_eq", "double", "20.0") + | 
|  | CreateFontconfigEditStanza("antialias", "bool", "false") + | 
|  | kFontconfigMatchFooter + | 
|  | kFontconfigFileFooter)); | 
|  |  | 
|  | FontRenderParams params = GetFontRenderParams( | 
|  | FontRenderParamsQuery(), NULL); | 
|  | EXPECT_TRUE(params.antialiasing); | 
|  | EXPECT_TRUE(params.autohinter); | 
|  | EXPECT_TRUE(params.use_bitmaps); | 
|  | EXPECT_EQ(FontRenderParams::HINTING_SLIGHT, params.hinting); | 
|  | EXPECT_FALSE(params.subpixel_positioning); | 
|  | EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_RGB, | 
|  | params.subpixel_rendering); | 
|  | } | 
|  |  | 
|  | TEST_F(FontRenderParamsTest, Size) { | 
|  | ASSERT_TRUE(LoadSystemFontIntoFontconfig("arial.ttf")); | 
|  | ASSERT_TRUE(LoadConfigDataIntoFontconfig(temp_dir_.path(), | 
|  | std::string(kFontconfigFileHeader) + | 
|  | kFontconfigMatchPatternHeader + | 
|  | CreateFontconfigEditStanza("antialias", "bool", "true") + | 
|  | CreateFontconfigEditStanza("hinting", "bool", "true") + | 
|  | CreateFontconfigEditStanza("hintstyle", "const", "hintfull") + | 
|  | CreateFontconfigEditStanza("rgba", "const", "none") + | 
|  | kFontconfigMatchFooter + | 
|  | kFontconfigMatchPatternHeader + | 
|  | CreateFontconfigTestStanza("pixelsize", "less_eq", "double", "10") + | 
|  | CreateFontconfigEditStanza("antialias", "bool", "false") + | 
|  | kFontconfigMatchFooter + | 
|  | kFontconfigMatchPatternHeader + | 
|  | CreateFontconfigTestStanza("size", "more_eq", "double", "20") + | 
|  | CreateFontconfigEditStanza("hintstyle", "const", "hintslight") + | 
|  | CreateFontconfigEditStanza("rgba", "const", "rgb") + | 
|  | kFontconfigMatchFooter + | 
|  | kFontconfigFileFooter)); | 
|  |  | 
|  | // The defaults should be used when the supplied size isn't matched by the | 
|  | // second or third blocks. | 
|  | FontRenderParamsQuery query; | 
|  | query.pixel_size = 12; | 
|  | FontRenderParams params = GetFontRenderParams(query, NULL); | 
|  | EXPECT_TRUE(params.antialiasing); | 
|  | EXPECT_EQ(FontRenderParams::HINTING_FULL, params.hinting); | 
|  | EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_NONE, | 
|  | params.subpixel_rendering); | 
|  |  | 
|  | query.pixel_size = 10; | 
|  | params = GetFontRenderParams(query, NULL); | 
|  | EXPECT_FALSE(params.antialiasing); | 
|  | EXPECT_EQ(FontRenderParams::HINTING_FULL, params.hinting); | 
|  | EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_NONE, | 
|  | params.subpixel_rendering); | 
|  |  | 
|  | query.pixel_size = 0; | 
|  | query.point_size = 20; | 
|  | params = GetFontRenderParams(query, NULL); | 
|  | EXPECT_TRUE(params.antialiasing); | 
|  | EXPECT_EQ(FontRenderParams::HINTING_SLIGHT, params.hinting); | 
|  | EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_RGB, | 
|  | params.subpixel_rendering); | 
|  | } | 
|  |  | 
|  | TEST_F(FontRenderParamsTest, Style) { | 
|  | ASSERT_TRUE(LoadSystemFontIntoFontconfig("arial.ttf")); | 
|  | // Load a config that disables subpixel rendering for bold text and disables | 
|  | // hinting for italic text. | 
|  | ASSERT_TRUE(LoadConfigDataIntoFontconfig(temp_dir_.path(), | 
|  | std::string(kFontconfigFileHeader) + | 
|  | kFontconfigMatchPatternHeader + | 
|  | CreateFontconfigEditStanza("antialias", "bool", "true") + | 
|  | CreateFontconfigEditStanza("hinting", "bool", "true") + | 
|  | CreateFontconfigEditStanza("hintstyle", "const", "hintslight") + | 
|  | CreateFontconfigEditStanza("rgba", "const", "rgb") + | 
|  | kFontconfigMatchFooter + | 
|  | kFontconfigMatchPatternHeader + | 
|  | CreateFontconfigTestStanza("weight", "eq", "const", "bold") + | 
|  | CreateFontconfigEditStanza("rgba", "const", "none") + | 
|  | kFontconfigMatchFooter + | 
|  | kFontconfigMatchPatternHeader + | 
|  | CreateFontconfigTestStanza("slant", "eq", "const", "italic") + | 
|  | CreateFontconfigEditStanza("hinting", "bool", "false") + | 
|  | kFontconfigMatchFooter + | 
|  | kFontconfigFileFooter)); | 
|  |  | 
|  | FontRenderParamsQuery query; | 
|  | query.style = Font::NORMAL; | 
|  | FontRenderParams params = GetFontRenderParams(query, NULL); | 
|  | EXPECT_EQ(FontRenderParams::HINTING_SLIGHT, params.hinting); | 
|  | EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_RGB, | 
|  | params.subpixel_rendering); | 
|  |  | 
|  | query.style = Font::BOLD; | 
|  | params = GetFontRenderParams(query, NULL); | 
|  | EXPECT_EQ(FontRenderParams::HINTING_SLIGHT, params.hinting); | 
|  | EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_NONE, | 
|  | params.subpixel_rendering); | 
|  |  | 
|  | query.style = Font::ITALIC; | 
|  | params = GetFontRenderParams(query, NULL); | 
|  | EXPECT_EQ(FontRenderParams::HINTING_NONE, params.hinting); | 
|  | EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_RGB, | 
|  | params.subpixel_rendering); | 
|  |  | 
|  | query.style = Font::BOLD | Font::ITALIC; | 
|  | params = GetFontRenderParams(query, NULL); | 
|  | EXPECT_EQ(FontRenderParams::HINTING_NONE, params.hinting); | 
|  | EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_NONE, | 
|  | params.subpixel_rendering); | 
|  | } | 
|  |  | 
|  | TEST_F(FontRenderParamsTest, Scalable) { | 
|  | // Load a config that only enables antialiasing for scalable fonts. | 
|  | ASSERT_TRUE(LoadConfigDataIntoFontconfig(temp_dir_.path(), | 
|  | std::string(kFontconfigFileHeader) + | 
|  | kFontconfigMatchPatternHeader + | 
|  | CreateFontconfigEditStanza("antialias", "bool", "false") + | 
|  | kFontconfigMatchFooter + | 
|  | kFontconfigMatchPatternHeader + | 
|  | CreateFontconfigTestStanza("scalable", "eq", "bool", "true") + | 
|  | CreateFontconfigEditStanza("antialias", "bool", "true") + | 
|  | kFontconfigMatchFooter + | 
|  | kFontconfigFileFooter)); | 
|  |  | 
|  | // Check that we specifically ask how scalable fonts should be rendered. | 
|  | FontRenderParams params = GetFontRenderParams( | 
|  | FontRenderParamsQuery(), NULL); | 
|  | EXPECT_TRUE(params.antialiasing); | 
|  | } | 
|  |  | 
|  | TEST_F(FontRenderParamsTest, UseBitmaps) { | 
|  | ASSERT_TRUE(LoadSystemFontIntoFontconfig("arial.ttf")); | 
|  | // Load a config that enables embedded bitmaps for fonts <= 10 pixels. | 
|  | ASSERT_TRUE(LoadConfigDataIntoFontconfig(temp_dir_.path(), | 
|  | std::string(kFontconfigFileHeader) + | 
|  | kFontconfigMatchPatternHeader + | 
|  | CreateFontconfigEditStanza("embeddedbitmap", "bool", "false") + | 
|  | kFontconfigMatchFooter + | 
|  | kFontconfigMatchPatternHeader + | 
|  | CreateFontconfigTestStanza("pixelsize", "less_eq", "double", "10") + | 
|  | CreateFontconfigEditStanza("embeddedbitmap", "bool", "true") + | 
|  | kFontconfigMatchFooter + | 
|  | kFontconfigFileFooter)); | 
|  |  | 
|  | FontRenderParamsQuery query; | 
|  | FontRenderParams params = GetFontRenderParams(query, NULL); | 
|  | EXPECT_FALSE(params.use_bitmaps); | 
|  |  | 
|  | query.pixel_size = 5; | 
|  | params = GetFontRenderParams(query, NULL); | 
|  | EXPECT_TRUE(params.use_bitmaps); | 
|  | } | 
|  |  | 
|  | TEST_F(FontRenderParamsTest, ForceFullHintingWhenAntialiasingIsDisabled) { | 
|  | // Load a config that disables antialiasing and hinting while requesting | 
|  | // subpixel rendering. | 
|  | ASSERT_TRUE(LoadConfigDataIntoFontconfig(temp_dir_.path(), | 
|  | std::string(kFontconfigFileHeader) + | 
|  | kFontconfigMatchPatternHeader + | 
|  | CreateFontconfigEditStanza("antialias", "bool", "false") + | 
|  | CreateFontconfigEditStanza("hinting", "bool", "false") + | 
|  | CreateFontconfigEditStanza("hintstyle", "const", "hintnone") + | 
|  | CreateFontconfigEditStanza("rgba", "const", "rgb") + | 
|  | kFontconfigMatchFooter + | 
|  | kFontconfigFileFooter)); | 
|  |  | 
|  | // Full hinting should be forced. See the comment in GetFontRenderParams() for | 
|  | // more information. | 
|  | FontRenderParams params = GetFontRenderParams( | 
|  | FontRenderParamsQuery(), NULL); | 
|  | EXPECT_FALSE(params.antialiasing); | 
|  | EXPECT_EQ(FontRenderParams::HINTING_FULL, params.hinting); | 
|  | EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_NONE, | 
|  | params.subpixel_rendering); | 
|  | EXPECT_FALSE(params.subpixel_positioning); | 
|  | } | 
|  |  | 
|  | #if defined(OS_CHROMEOS) | 
|  | TEST_F(FontRenderParamsTest, ForceSubpixelPositioning) { | 
|  | { | 
|  | FontRenderParams params = | 
|  | GetFontRenderParams(FontRenderParamsQuery(), NULL); | 
|  | EXPECT_TRUE(params.antialiasing); | 
|  | EXPECT_FALSE(params.subpixel_positioning); | 
|  | SetFontRenderParamsDeviceScaleFactor(1.0f); | 
|  | } | 
|  | ClearFontRenderParamsCacheForTest(); | 
|  | SetFontRenderParamsDeviceScaleFactor(1.25f); | 
|  | // Subpixel positioning should be forced. | 
|  | { | 
|  | FontRenderParams params = | 
|  | GetFontRenderParams(FontRenderParamsQuery(), NULL); | 
|  | EXPECT_TRUE(params.antialiasing); | 
|  | EXPECT_TRUE(params.subpixel_positioning); | 
|  | SetFontRenderParamsDeviceScaleFactor(1.0f); | 
|  | } | 
|  | } | 
|  | #endif | 
|  |  | 
|  | TEST_F(FontRenderParamsTest, OnlySetConfiguredValues) { | 
|  | // Configure the LinuxFontDelegate (which queries GtkSettings on desktop | 
|  | // Linux) to request subpixel rendering. | 
|  | FontRenderParams system_params; | 
|  | system_params.subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_RGB; | 
|  | test_font_delegate_.set_params(system_params); | 
|  |  | 
|  | // Load a Fontconfig config that enables antialiasing but doesn't say anything | 
|  | // about subpixel rendering. | 
|  | ASSERT_TRUE(LoadConfigDataIntoFontconfig(temp_dir_.path(), | 
|  | std::string(kFontconfigFileHeader) + | 
|  | kFontconfigMatchPatternHeader + | 
|  | CreateFontconfigEditStanza("antialias", "bool", "true") + | 
|  | kFontconfigMatchFooter + | 
|  | kFontconfigFileFooter)); | 
|  |  | 
|  | // The subpixel rendering setting from the delegate should make it through. | 
|  | FontRenderParams params = GetFontRenderParams( | 
|  | FontRenderParamsQuery(), NULL); | 
|  | EXPECT_EQ(system_params.subpixel_rendering, params.subpixel_rendering); | 
|  | } | 
|  |  | 
|  | TEST_F(FontRenderParamsTest, NoFontconfigMatch) { | 
|  | // Don't load a Fontconfig configuration. | 
|  | FontRenderParams system_params; | 
|  | system_params.antialiasing = true; | 
|  | system_params.hinting = FontRenderParams::HINTING_MEDIUM; | 
|  | system_params.subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_RGB; | 
|  | test_font_delegate_.set_params(system_params); | 
|  |  | 
|  | FontRenderParamsQuery query; | 
|  | query.families.push_back("Arial"); | 
|  | query.families.push_back("Times New Roman"); | 
|  | query.pixel_size = 10; | 
|  | std::string suggested_family; | 
|  | FontRenderParams params = GetFontRenderParams(query, &suggested_family); | 
|  |  | 
|  | // The system params and the first requested family should be returned. | 
|  | EXPECT_EQ(system_params.antialiasing, params.antialiasing); | 
|  | EXPECT_EQ(system_params.hinting, params.hinting); | 
|  | EXPECT_EQ(system_params.subpixel_rendering, params.subpixel_rendering); | 
|  | EXPECT_EQ(query.families[0], suggested_family); | 
|  | } | 
|  |  | 
|  | TEST_F(FontRenderParamsTest, MissingFamily) { | 
|  | // With Arial and Verdana installed, request (in order) Helvetica, Arial, and | 
|  | // Verdana and check that Arial is returned. | 
|  | ASSERT_TRUE(LoadSystemFontIntoFontconfig("arial.ttf")); | 
|  | ASSERT_TRUE(LoadSystemFontIntoFontconfig("verdana.ttf")); | 
|  | FontRenderParamsQuery query; | 
|  | query.families.push_back("Helvetica"); | 
|  | query.families.push_back("Arial"); | 
|  | query.families.push_back("Verdana"); | 
|  | std::string suggested_family; | 
|  | GetFontRenderParams(query, &suggested_family); | 
|  | EXPECT_EQ("Arial", suggested_family); | 
|  | } | 
|  |  | 
|  | TEST_F(FontRenderParamsTest, SubstituteFamily) { | 
|  | // Configure Fontconfig to use Verdana for both Helvetica and Arial. | 
|  | ASSERT_TRUE(LoadSystemFontIntoFontconfig("arial.ttf")); | 
|  | ASSERT_TRUE(LoadSystemFontIntoFontconfig("verdana.ttf")); | 
|  | ASSERT_TRUE(LoadConfigDataIntoFontconfig(temp_dir_.path(), | 
|  | std::string(kFontconfigFileHeader) + | 
|  | CreateFontconfigAliasStanza("Helvetica", "Verdana") + | 
|  | kFontconfigMatchPatternHeader + | 
|  | CreateFontconfigTestStanza("family", "eq", "string", "Arial") + | 
|  | CreateFontconfigEditStanza("family", "string", "Verdana") + | 
|  | kFontconfigMatchFooter + | 
|  | kFontconfigFileFooter)); | 
|  |  | 
|  | FontRenderParamsQuery query; | 
|  | query.families.push_back("Helvetica"); | 
|  | std::string suggested_family; | 
|  | GetFontRenderParams(query, &suggested_family); | 
|  | EXPECT_EQ("Verdana", suggested_family); | 
|  |  | 
|  | query.families.clear(); | 
|  | query.families.push_back("Arial"); | 
|  | suggested_family.clear(); | 
|  | GetFontRenderParams(query, &suggested_family); | 
|  | EXPECT_EQ("Verdana", suggested_family); | 
|  | } | 
|  |  | 
|  | }  // namespace gfx |