// 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(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