blob: 1ade1afd92fbf8de07a88f73a04b60b3f7285855 [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 "topaz/runtime/flutter_runner/fuchsia_font_manager.h"
#include <fcntl.h>
#include <fuchsia/fonts/cpp/fidl.h>
#include <fuchsia/sys/cpp/fidl.h>
#include <lib/fdio/fd.h>
#include <lib/gtest/real_loop_fixture.h>
#include <lib/sys/cpp/service_directory.h>
#include <lib/zx/channel.h>
#include <lib/zx/handle.h>
#include <memory>
#include "gtest/gtest.h"
#include "third_party/skia/include/core/SkFontMgr.h"
#include "third_party/skia/include/core/SkTypeface.h"
namespace {
zx::channel CloneChannelFromFileDescriptor(int fd) {
zx::handle handle;
zx_status_t status = fdio_fd_clone(fd, handle.reset_and_get_address());
if (status != ZX_OK)
return zx::channel();
zx_info_handle_basic_t info = {};
status =
handle.get_info(ZX_INFO_HANDLE_BASIC, &info, sizeof(info), NULL, NULL);
if (status != ZX_OK || info.type != ZX_OBJ_TYPE_CHANNEL)
return zx::channel();
return zx::channel(handle.release());
}
} // namespace
namespace txt {
namespace {
// A codepoint guaranteed to be unknown in any font/family.
constexpr SkUnichar kUnknownUnicodeCharacter = 0xFFF0;
// Font family to use for tests.
constexpr char kTestFontFamily[] = "Roboto";
// URL for the fonts service.
constexpr char kFontsServiceUrl[] =
"fuchsia-pkg://fuchsia.com/fonts#meta/fonts.cmx";
class FuchsiaFontManagerTest : public gtest::RealLoopFixture {
public:
FuchsiaFontManagerTest() {
auto services = sys::ServiceDirectory::CreateFromNamespace();
// Grab launcher and launch font provider.
fuchsia::sys::LauncherPtr launcher;
services->Connect(launcher.NewRequest());
zx::channel out_services_request;
auto font_services =
sys::ServiceDirectory::CreateWithRequest(&out_services_request);
auto launch_info_font_service = GetLaunchInfoForFontService();
launch_info_font_service.directory_request =
std::move(out_services_request);
launcher->CreateComponent(std::move(launch_info_font_service),
font_service_controller_.NewRequest());
// Connect to the font provider service and then wrap it inside the font
// manager we will be testing.
fuchsia::fonts::ProviderSyncPtr provider_ptr;
font_services->Connect(provider_ptr.NewRequest());
font_manager_ = sk_make_sp<FuchsiaFontManager>(std::move(provider_ptr));
}
fuchsia::sys::LaunchInfo GetLaunchInfoForFontService() {
fuchsia::sys::LaunchInfo launch_info;
launch_info.url = kFontsServiceUrl;
launch_info.arguments.reset(
{"--no-default-fonts", "--font-manifest=/test_fonts/manifest.json"});
auto tmp_dir_fd = open("/pkg/data/testdata/test_fonts",
O_DIRECTORY | O_RDONLY);
launch_info.flat_namespace = fuchsia::sys::FlatNamespace::New();
launch_info.flat_namespace->paths.push_back("/test_fonts");
launch_info.flat_namespace->directories.push_back(
CloneChannelFromFileDescriptor(tmp_dir_fd));
close(tmp_dir_fd);
return launch_info;
}
protected:
fuchsia::sys::ComponentControllerPtr font_service_controller_;
sk_sp<SkFontMgr> font_manager_;
};
// Verify that a typeface is returned for a found character.
TEST_F(FuchsiaFontManagerTest, ValidResponseWhenCharacterFound) {
sk_sp<SkTypeface> typeface(font_manager_->matchFamilyStyleCharacter(
"", SkFontStyle(), nullptr, 0, '&'));
EXPECT_TRUE(typeface.get() != nullptr);
}
// Verify that a codepoint that doesn't map to a character correctly returns
// an empty typeface.
TEST_F(FuchsiaFontManagerTest, EmptyResponseWhenCharacterNotFound) {
sk_sp<SkTypeface> typeface(font_manager_->matchFamilyStyleCharacter(
"", SkFontStyle(), nullptr, 0, kUnknownUnicodeCharacter));
EXPECT_TRUE(typeface.get() == nullptr);
}
// Verify that SkTypeface objects are cached.
TEST_F(FuchsiaFontManagerTest, Caching) {
sk_sp<SkTypeface> typeface(
font_manager_->matchFamilyStyle(kTestFontFamily, SkFontStyle()));
sk_sp<SkTypeface> typeface2(
font_manager_->matchFamilyStyle(kTestFontFamily, SkFontStyle()));
// Expect that the same SkTypeface is returned for both requests.
EXPECT_EQ(typeface.get(), typeface2.get());
// Request a different typeface and verify that a different SkTypeface is
// returned.
sk_sp<SkTypeface> typeface3(
font_manager_->matchFamilyStyle("Roboto Slab", SkFontStyle()));
EXPECT_NE(typeface.get(), typeface3.get());
}
// Verify that SkTypeface can outlive the manager.
TEST_F(FuchsiaFontManagerTest, TypefaceOutlivesManager) {
sk_sp<SkTypeface> typeface(
font_manager_->matchFamilyStyle(kTestFontFamily, SkFontStyle()));
font_manager_.reset();
EXPECT_TRUE(typeface.get() != nullptr);
}
// Verify that we can query a font after releasing a previous instance.
TEST_F(FuchsiaFontManagerTest, ReleaseThenCreateAgain) {
sk_sp<SkTypeface> typeface(
font_manager_->matchFamilyStyle(kTestFontFamily, SkFontStyle()));
EXPECT_TRUE(typeface != nullptr);
typeface.reset();
sk_sp<SkTypeface> typeface2(
font_manager_->matchFamilyStyle(kTestFontFamily, SkFontStyle()));
EXPECT_TRUE(typeface2 != nullptr);
}
// Verify that we get a new typeface instance after releasing a previous
// instance of the same typeface (i.e. the cache purges the released typeface).
TEST_F(FuchsiaFontManagerTest, ReleasedTypefaceIsPurged) {
sk_sp<SkTypeface> typeface(
font_manager_->matchFamilyStyle(kTestFontFamily, SkFontStyle()));
EXPECT_TRUE(typeface != nullptr);
typeface.reset();
sk_sp<SkTypeface> typeface2(
font_manager_->matchFamilyStyle(kTestFontFamily, SkFontStyle()));
EXPECT_TRUE(typeface2 != nullptr);
EXPECT_NE(typeface.get(), typeface2.get());
}
// Verify that unknown font families are handled correctly.
TEST_F(FuchsiaFontManagerTest, MatchUnknownFamily) {
SkFontStyleSet* style_set = font_manager_->matchFamily("unknown");
EXPECT_TRUE(style_set == nullptr || style_set->count() == 0);
}
// Verify that a style set is returned for a known family.
TEST_F(FuchsiaFontManagerTest, MatchKnownFamily) {
SkFontStyleSet* style_set = font_manager_->matchFamily(kTestFontFamily);
EXPECT_GT(style_set->count(), 0);
}
// Verify getting an SkFontStyle from a matched family.
TEST_F(FuchsiaFontManagerTest, FontFamilyGetStyle) {
SkFontStyleSet* style_set = font_manager_->matchFamily(kTestFontFamily);
SkFontStyle style;
style_set->getStyle(0, &style, nullptr);
EXPECT_EQ(style.weight(), 400);
EXPECT_EQ(style.width(), 5);
EXPECT_EQ(style.slant(), SkFontStyle::kUpright_Slant);
}
// Verify creating a typeface from a matched family.
TEST_F(FuchsiaFontManagerTest, FontFamilyCreateTypeface) {
SkFontStyleSet* style_set = font_manager_->matchFamily(kTestFontFamily);
SkTypeface* typeface = style_set->createTypeface(0);
EXPECT_TRUE(typeface != nullptr);
SkFontStyle style = typeface->fontStyle();
EXPECT_EQ(style.weight(), 400);
EXPECT_EQ(style.width(), 5);
EXPECT_EQ(style.slant(), SkFontStyle::kUpright_Slant);
}
} // namespace
} // namespace txt