blob: 365c8d8981a9a531465a0fd97205ac60c02905fb [file] [log] [blame]
// Copyright 2016 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 "garnet/bin/fonts/font_provider_impl.h"
#include <string.h>
#include <zircon/status.h>
#include <zircon/syscalls.h>
#include <utility>
#include "lib/fxl/files/file.h"
#include "lib/fxl/logging.h"
#include "third_party/rapidjson/rapidjson/document.h"
#include "third_party/rapidjson/rapidjson/rapidjson.h"
namespace fonts {
namespace {
constexpr char kFontManifestPath[] = "/pkg/data/manifest.json";
constexpr char kFallback[] = "fallback";
constexpr char kFamilies[] = "families";
constexpr zx_rights_t kFontDataRights =
ZX_RIGHTS_BASIC | ZX_RIGHT_READ | ZX_RIGHT_MAP;
} // namespace
FontProviderImpl::FontProviderImpl() = default;
FontProviderImpl::~FontProviderImpl() = default;
bool FontProviderImpl::LoadFontsInternal() {
std::string json_data;
if (!files::ReadFileToString(kFontManifestPath, &json_data)) {
FXL_LOG(ERROR) << "Failed to read font manifest from '" << kFontManifestPath
<< "'.";
return false;
}
rapidjson::Document document;
document.Parse(json_data.data());
if (document.HasParseError() || !document.IsObject()) {
FXL_LOG(ERROR) << "Font manifest was not vaild JSON.";
return false;
}
const auto& fallback = document.FindMember(kFallback);
if (fallback == document.MemberEnd() || !fallback->value.IsString()) {
FXL_LOG(ERROR)
<< "Font manifest did not contain a valid 'fallback' family.";
return false;
}
fallback_ = fallback->value.GetString();
const auto& families = document.FindMember(kFamilies);
if (families == document.MemberEnd() || !families->value.IsArray()) {
FXL_LOG(ERROR) << "Font manifest did not contain any families.";
return false;
}
for (const auto& family : families->value.GetArray()) {
auto parsed_family = std::make_unique<FontFamily>();
if (!parsed_family->Load(family))
return false;
std::string name = parsed_family->name();
families_.emplace(name, std::move(parsed_family));
}
if (families_.find(fallback_) == families_.end()) {
FXL_LOG(ERROR) << "Font manifest did not contain '" << fallback_
<< "', which is the fallback family.";
return false;
}
return true;
}
bool FontProviderImpl::LoadFonts() {
bool loaded_all = LoadFontsInternal();
if (!loaded_all)
Reset();
return loaded_all;
}
void FontProviderImpl::Reset() {
fallback_.clear();
families_.clear();
}
void FontProviderImpl::AddBinding(
fidl::InterfaceRequest<FontProvider> request) {
bindings_.AddBinding(this, std::move(request));
}
void FontProviderImpl::GetFont(FontRequestPtr request,
const GetFontCallback& callback) {
if (families_.empty()) {
callback(nullptr);
return;
}
auto it = families_.find(request->family);
if (it == families_.end())
it = families_.find(fallback_);
if (it == families_.end()) {
callback(nullptr);
return;
}
zx::vmo* font_data = it->second->GetFontData(request);
if (!font_data) {
callback(nullptr);
return;
}
auto data = FontData::New();
if (font_data->duplicate(kFontDataRights, &data->vmo) < 0) {
callback(nullptr);
return;
}
auto response = FontResponse::New();
response->data = std::move(data);
callback(std::move(response));
}
} // namespace fonts