blob: d7415cc0474dc0fbf316c8ec6ea9953b9713ad00 [file] [log] [blame]
// Copyright 2017 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_family.h"
#include <algorithm>
#include "lib/fxl/logging.h"
#include "lib/fsl/vmo/file.h"
namespace fonts {
namespace {
constexpr char kFamily[] = "family";
constexpr char kFonts[] = "fonts";
constexpr char kAsset[] = "asset";
constexpr char kSlant[] = "slant";
constexpr char kWeight[] = "weight";
constexpr char kItalic[] = "italic";
constexpr char kUpright[] = "upright";
struct Matcher {
Matcher(FontSlant slant, int weight)
: slant_(slant), weight_(weight) {}
bool operator()(const FontFamily::Font& a,
const FontFamily::Font& b) {
if (a.slant != b.slant) {
if (a.slant == slant_)
return true;
if (b.slant == slant_)
return false;
}
return abs(a.weight - weight_) < abs(b.weight - weight_);
}
private:
FontSlant slant_;
int weight_;
};
} // namespace
FontFamily::Font::Font() : slant(FontSlant::UPRIGHT), weight(400) {}
FontFamily::Font::Font(Font&& other)
: asset(std::move(other.asset)),
slant(std::move(other.slant)),
weight(std::move(other.weight)),
data(std::move(other.data)) {}
FontFamily::FontFamily() = default;
FontFamily::~FontFamily() = default;
bool FontFamily::Load(const rapidjson::Document::ValueType& family) {
if (!family.IsObject()) {
FXL_LOG(ERROR) << "Font manifest contained an invalid family.";
return false;
}
const auto& name = family.FindMember(kFamily);
if (name == family.MemberEnd() || !name->value.IsString()) {
FXL_LOG(ERROR) << "Font manifest contained a family without a valid name.";
return false;
}
name_ = name->value.GetString();
const auto& fonts = family.FindMember(kFonts);
if (fonts == family.MemberEnd() || !fonts->value.IsArray()) {
FXL_LOG(ERROR) << "Font family '" << name_ << "' did not contain any fonts.";
return false;
}
for (const auto& font : fonts->value.GetArray()) {
if (!font.IsObject()) {
FXL_LOG(ERROR) << "Font family '" << name_ << "' contained an invalid font.";
return false;
}
Font record;
const auto& asset = font.FindMember(kAsset);
if (asset == font.MemberEnd() || !asset->value.IsString()) {
FXL_LOG(ERROR) << "Font family '" << name_
<< "' contained a font without a valid asset.";
return false;
}
record.asset = asset->value.GetString();
const auto& slant = font.FindMember(kSlant);
if (slant != font.MemberEnd()) {
if (!slant->value.IsString()) {
FXL_LOG(ERROR) << "Font family '" << name_
<< "' contained a font whose slant was not a string.";
return false;
}
std::string slant_string = slant->value.GetString();
if (slant_string == kItalic) {
record.slant = FontSlant::ITALIC;
} else if (slant_string != kUpright) {
FXL_LOG(ERROR) << "Font family '" << name_
<< "' contained a font with slant '" << slant_string
<< "', which is not valid.";
return false;
}
}
const auto& weight = font.FindMember(kWeight);
if (weight != font.MemberEnd()) {
if (!weight->value.IsInt()) {
FXL_LOG(ERROR) << "Font family '" << name_
<< "' contained a font whose weight was not an integer.";
return false;
}
record.weight = weight->value.GetInt();
}
fonts_.push_back(std::move(record));
}
return true;
}
zx::vmo* FontFamily::GetFontData(const FontRequestPtr& request) {
Matcher matcher(request->slant, request->weight);
auto it = std::min_element(fonts_.begin(), fonts_.end(), matcher);
if (it == fonts_.end())
return nullptr;
if (it->data.is_valid())
return &it->data;
if (fsl::VmoFromFilename(it->asset, &it->data))
return &it->data;
return nullptr;
}
}