123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459 |
- // 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 <fontconfig/fontconfig.h>
- #include "base/check_op.h"
- #include "base/files/file_util.h"
- #include "base/files/scoped_temp_dir.h"
- #include "base/memory/raw_ptr.h"
- #include "base/notreached.h"
- #include "base/strings/stringprintf.h"
- #include "build/build_config.h"
- #include "build/chromeos_buildflags.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/test_fonts/fontconfig/fontconfig_util_linux.h"
- #include "ui/gfx/font.h"
- #include "ui/gfx/linux/fontconfig_util.h"
- #include "ui/linux/fake_linux_ui.h"
- namespace gfx {
- namespace {
- // Strings appearing at the beginning and end of Fontconfig XML files.
- const char kFontconfigFileHeader[] =
- "<?xml version=\"1.0\"?>\n"
- "<!DOCTYPE fontconfig SYSTEM \"fonts.dtd\">\n"
- "<fontconfig>\n";
- const char kFontconfigFileFooter[] = "</fontconfig>";
- // Strings appearing at the beginning and end of Fontconfig <match> stanzas.
- const char kFontconfigMatchFontHeader[] = " <match target=\"font\">\n";
- const char kFontconfigMatchPatternHeader[] = " <match target=\"pattern\">\n";
- const char kFontconfigMatchFooter[] = " </match>\n";
- // Implementation of LinuxUi that returns a canned FontRenderParams
- // struct. This is used to isolate tests from the system's local configuration.
- class TestFontDelegate : public ui::FakeLinuxUi {
- public:
- TestFontDelegate() = default;
- TestFontDelegate(const TestFontDelegate&) = delete;
- TestFontDelegate& operator=(const TestFontDelegate&) = delete;
- ~TestFontDelegate() override = default;
- 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,
- int* weight_out,
- FontRenderParams* params_out) const override {
- NOTIMPLEMENTED();
- }
- private:
- FontRenderParams params_;
- };
- // Loads XML-formatted |data| into the current font configuration.
- bool LoadConfigDataIntoFontconfig(const std::string& data) {
- FcConfig* config = GetGlobalFontConfig();
- constexpr FcBool kComplain = FcTrue;
- return FcConfigParseAndLoadFromMemory(
- config, reinterpret_cast<const FcChar8*>(data.c_str()), kComplain);
- }
- // Returns a Fontconfig <edit> stanza.
- std::string CreateFontconfigEditStanza(const std::string& name,
- const std::string& type,
- const std::string& value) {
- return base::StringPrintf(
- " <edit name=\"%s\" mode=\"assign\">\n"
- " <%s>%s</%s>\n"
- " </edit>\n",
- name.c_str(), type.c_str(), value.c_str(), type.c_str());
- }
- // Returns a Fontconfig <test> stanza.
- std::string CreateFontconfigTestStanza(const std::string& name,
- const std::string& op,
- const std::string& type,
- const std::string& value) {
- return base::StringPrintf(
- " <test name=\"%s\" compare=\"%s\" qual=\"any\">\n"
- " <%s>%s</%s>\n"
- " </test>\n",
- name.c_str(), op.c_str(), type.c_str(), value.c_str(), type.c_str());
- }
- // Returns a Fontconfig <alias> stanza.
- std::string CreateFontconfigAliasStanza(const std::string& original_family,
- const std::string& preferred_family) {
- return base::StringPrintf(
- " <alias>\n"
- " <family>%s</family>\n"
- " <prefer><family>%s</family></prefer>\n"
- " </alias>\n",
- original_family.c_str(), preferred_family.c_str());
- }
- } // namespace
- class FontRenderParamsTest : public testing::Test {
- public:
- FontRenderParamsTest() {
- auto test_font_delegate = std::make_unique<TestFontDelegate>();
- test_font_delegate_ = test_font_delegate.get();
- ui::LinuxUi::SetInstance(std::move(test_font_delegate));
- ClearFontRenderParamsCacheForTest();
- // Create a new fontconfig configuration and load the default fonts
- // configuration. The default test config file is produced in the build
- // folder under <build_dir>/etc/fonts/fonts.conf and the loaded tests fonts
- // are under <build_dir>/test_fonts.
- override_config_ = FcConfigCreate();
- FcBool parse_success =
- FcConfigParseAndLoad(override_config_, nullptr, FcTrue);
- DCHECK_NE(parse_success, FcFalse);
- FcBool load_success = FcConfigBuildFonts(override_config_);
- DCHECK_NE(load_success, FcFalse);
- original_config_ = GetGlobalFontConfig();
- OverrideGlobalFontConfigForTesting(override_config_);
- }
- FontRenderParamsTest(const FontRenderParamsTest&) = delete;
- FontRenderParamsTest& operator=(const FontRenderParamsTest&) = delete;
- ~FontRenderParamsTest() override {
- OverrideGlobalFontConfigForTesting(original_config_);
- FcConfigDestroy(override_config_);
- ui::LinuxUi::SetInstance(nullptr);
- test_font_delegate_ = nullptr;
- }
- protected:
- raw_ptr<TestFontDelegate> test_font_delegate_;
- raw_ptr<FcConfig> override_config_ = nullptr;
- raw_ptr<FcConfig> original_config_ = nullptr;
- };
- TEST_F(FontRenderParamsTest, Default) {
- ASSERT_TRUE(LoadConfigDataIntoFontconfig(
- 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 Arimo. Since it specifies a family, it
- // shouldn't take effect when querying default settings.
- kFontconfigMatchFontHeader +
- CreateFontconfigTestStanza("family", "eq", "string", "Arimo") +
- 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(), nullptr);
- 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(LoadConfigDataIntoFontconfig(
- 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, nullptr);
- 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, nullptr);
- 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, nullptr);
- EXPECT_TRUE(params.antialiasing);
- EXPECT_EQ(FontRenderParams::HINTING_SLIGHT, params.hinting);
- EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_RGB,
- params.subpixel_rendering);
- }
- TEST_F(FontRenderParamsTest, Style) {
- // Load a config that disables subpixel rendering for bold text and disables
- // hinting for italic text.
- ASSERT_TRUE(LoadConfigDataIntoFontconfig(
- 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, nullptr);
- EXPECT_EQ(FontRenderParams::HINTING_SLIGHT, params.hinting);
- EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_RGB,
- params.subpixel_rendering);
- query.weight = Font::Weight::BOLD;
- params = GetFontRenderParams(query, nullptr);
- EXPECT_EQ(FontRenderParams::HINTING_SLIGHT, params.hinting);
- EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_NONE,
- params.subpixel_rendering);
- query.weight = Font::Weight::NORMAL;
- query.style = Font::ITALIC;
- params = GetFontRenderParams(query, nullptr);
- EXPECT_EQ(FontRenderParams::HINTING_NONE, params.hinting);
- EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_RGB,
- params.subpixel_rendering);
- query.weight = Font::Weight::BOLD;
- query.style = Font::ITALIC;
- params = GetFontRenderParams(query, nullptr);
- 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(
- 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(), nullptr);
- EXPECT_TRUE(params.antialiasing);
- }
- TEST_F(FontRenderParamsTest, UseBitmaps) {
- // Load a config that enables embedded bitmaps for fonts <= 10 pixels.
- ASSERT_TRUE(LoadConfigDataIntoFontconfig(
- 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, nullptr);
- EXPECT_FALSE(params.use_bitmaps);
- query.pixel_size = 5;
- params = GetFontRenderParams(query, nullptr);
- EXPECT_TRUE(params.use_bitmaps);
- }
- TEST_F(FontRenderParamsTest, ForceFullHintingWhenAntialiasingIsDisabled) {
- // Load a config that disables antialiasing and hinting while requesting
- // subpixel rendering.
- ASSERT_TRUE(LoadConfigDataIntoFontconfig(
- 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(), nullptr);
- 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);
- }
- TEST_F(FontRenderParamsTest, ForceSubpixelPositioning) {
- {
- FontRenderParams params =
- GetFontRenderParams(FontRenderParamsQuery(), nullptr);
- 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(), nullptr);
- EXPECT_TRUE(params.antialiasing);
- EXPECT_TRUE(params.subpixel_positioning);
- SetFontRenderParamsDeviceScaleFactor(1.0f);
- }
- ClearFontRenderParamsCacheForTest();
- SetFontRenderParamsDeviceScaleFactor(2.f);
- // Subpixel positioning should be forced on non-Chrome-OS.
- {
- FontRenderParams params =
- GetFontRenderParams(FontRenderParamsQuery(), nullptr);
- EXPECT_TRUE(params.antialiasing);
- #if !BUILDFLAG(IS_CHROMEOS_ASH)
- EXPECT_TRUE(params.subpixel_positioning);
- #else
- // Integral scale factor does not require subpixel positioning.
- EXPECT_FALSE(params.subpixel_positioning);
- #endif // !BUILDFLAG(IS_CHROMEOS_ASH)
- SetFontRenderParamsDeviceScaleFactor(1.0f);
- }
- }
- TEST_F(FontRenderParamsTest, OnlySetConfiguredValues) {
- // Configure the LinuxUi 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(
- 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(), nullptr);
- EXPECT_EQ(system_params.subpixel_rendering, params.subpixel_rendering);
- }
- TEST_F(FontRenderParamsTest, NoFontconfigMatch) {
- // A default configuration was set up globally. Reset it to a blank config.
- FcConfig* blank = FcConfigCreate();
- OverrideGlobalFontConfigForTesting(blank);
- 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("Arimo");
- 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);
- OverrideGlobalFontConfigForTesting(override_config_);
- FcConfigDestroy(blank);
- }
- TEST_F(FontRenderParamsTest, MissingFamily) {
- // With Arimo and Verdana installed, request (in order) Helvetica, Arimo, and
- // Verdana and check that Arimo is returned.
- FontRenderParamsQuery query;
- query.families.push_back("Helvetica");
- query.families.push_back("Arimo");
- query.families.push_back("Verdana");
- std::string suggested_family;
- GetFontRenderParams(query, &suggested_family);
- EXPECT_EQ("Arimo", suggested_family);
- }
- TEST_F(FontRenderParamsTest, SubstituteFamily) {
- // Configure Fontconfig to use Tinos for both Helvetica and Arimo.
- ASSERT_TRUE(LoadConfigDataIntoFontconfig(
- std::string(kFontconfigFileHeader) +
- CreateFontconfigAliasStanza("Helvetica", "Tinos") +
- kFontconfigMatchPatternHeader +
- CreateFontconfigTestStanza("family", "eq", "string", "Arimo") +
- CreateFontconfigEditStanza("family", "string", "Tinos") +
- kFontconfigMatchFooter + kFontconfigFileFooter));
- FontRenderParamsQuery query;
- query.families.push_back("Helvetica");
- std::string suggested_family;
- GetFontRenderParams(query, &suggested_family);
- EXPECT_EQ("Tinos", suggested_family);
- query.families.clear();
- query.families.push_back("Arimo");
- suggested_family.clear();
- GetFontRenderParams(query, &suggested_family);
- EXPECT_EQ("Tinos", suggested_family);
- }
- } // namespace gfx
|