提交 89a92952 编写于 作者: J Jason Simmons

Match fonts based on weight and style attributes

上级 545f9000
......@@ -18,10 +18,6 @@
namespace sky {
namespace shell {
namespace {
const char kFontManifestAssetPath[] = "FontManifest.json";
}
using base::DictionaryValue;
using base::JSONReader;
using base::ListValue;
......@@ -32,9 +28,73 @@ using blink::FontData;
using blink::FontDescription;
using blink::FontFaceCreationParams;
using blink::FontPlatformData;
using blink::FontStyle;
using blink::FontWeight;
using blink::SimpleFontData;
using mojo::asset_bundle::ZipAssetBundle;
// Style attributes of a Flutter font asset.
struct FlutterFontSelector::FlutterFontAttributes {
FlutterFontAttributes(const std::string& path);
~FlutterFontAttributes();
std::string asset_path;
int weight;
FontStyle style;
};
// A Skia typeface along with a buffer holding the raw typeface asset data.
struct FlutterFontSelector::TypefaceAsset {
TypefaceAsset();
~TypefaceAsset();
RefPtr<SkTypeface> typeface;
std::vector<uint8_t> data;
};
namespace {
const char kFontManifestAssetPath[] = "FontManifest.json";
// Weight values corresponding to the members of the FontWeight enum.
const int kFontWeightValue[] = {100, 200, 300, 400, 500, 600, 700, 800, 900};
const int kFontWeightNormal = kFontWeightValue[FontWeight::FontWeightNormal];
int getFontWeightValue(FontWeight weight) {
size_t weight_index = weight;
return (weight_index < arraysize(kFontWeightValue)) ?
kFontWeightValue[weight_index] : kFontWeightNormal;
}
// Compares fonts within a family to determine which one most closely matches
// a FontDescription.
struct FontMatcher {
using FlutterFontAttributes = FlutterFontSelector::FlutterFontAttributes;
FontMatcher(const FontDescription& description)
: description_(description),
target_weight_(getFontWeightValue(description.weight())) {
}
bool operator()(const FlutterFontAttributes& font1,
const FlutterFontAttributes& font2) {
if (font1.style != font2.style) {
if (font1.style == description_.style())
return true;
if (font2.style == description_.style())
return false;
}
int weight_delta1 = abs(font1.weight - target_weight_);
int weight_delta2 = abs(font2.weight - target_weight_);
return weight_delta1 < weight_delta2;
}
private:
const FontDescription& description_;
int target_weight_;
};
}
void FlutterFontSelector::install(
const scoped_refptr<ZipAssetBundle>& zip_asset_bundle) {
RefPtr<FlutterFontSelector> font_selector = adoptRef(
......@@ -57,6 +117,16 @@ FlutterFontSelector::TypefaceAsset::TypefaceAsset() {
FlutterFontSelector::TypefaceAsset::~TypefaceAsset() {
}
FlutterFontSelector::FlutterFontAttributes::FlutterFontAttributes(
const std::string& path)
: asset_path(path),
weight(kFontWeightNormal),
style(FontStyle::FontStyleNormal) {
}
FlutterFontSelector::FlutterFontAttributes::~FlutterFontAttributes() {
}
void FlutterFontSelector::parseFontManifest() {
std::vector<uint8_t> font_manifest_data;
if (!zip_asset_bundle_->GetAsBuffer(kFontManifestAssetPath,
......@@ -86,21 +156,32 @@ void FlutterFontSelector::parseFontManifest() {
if (!family_dict->GetList("fonts", &font_list))
continue;
if (font_list->GetSize() != 1) {
LOG(WARNING) << "Font family " << family_name
<< " must have exactly one font";
continue;
}
DictionaryValue* font_dict;
if (!font_list->GetDictionary(0, &font_dict))
continue;
AtomicString family_key = AtomicString::fromUTF8(family_name.c_str());
auto set_result = font_family_map_.set(
family_key, std::vector<FlutterFontAttributes>());
std::vector<FlutterFontAttributes>& family_assets =
set_result.storedValue->value;
std::string asset_path;
if (!font_dict->GetString("asset", &asset_path))
continue;
for (Value* list_entry : *font_list) {
DictionaryValue* font_dict;
if (!list_entry->GetAsDictionary(&font_dict))
continue;
std::string asset_path;
if (!font_dict->GetString("asset", &asset_path))
continue;
FlutterFontAttributes attributes(asset_path);
font_dict->GetInteger("weight", &attributes.weight);
std::string style;
if (font_dict->GetString("style", &style)) {
if (style == "italic")
attributes.style = FontStyle::FontStyleItalic;
}
font_asset_path_map_.set(AtomicString::fromUTF8(family_name.c_str()),
AtomicString::fromUTF8(asset_path.c_str()));
family_assets.push_back(attributes);
}
}
}
......@@ -112,7 +193,7 @@ PassRefPtr<FontData> FlutterFontSelector::getFontData(
RefPtr<SimpleFontData> font_data = font_platform_data_cache_.get(key);
if (font_data == nullptr) {
SkTypeface* typeface = getTypefaceAsset(family_name);
SkTypeface* typeface = getTypefaceAsset(font_description, family_name);
if (typeface == nullptr)
return nullptr;
......@@ -139,21 +220,35 @@ PassRefPtr<FontData> FlutterFontSelector::getFontData(
}
SkTypeface* FlutterFontSelector::getTypefaceAsset(
const FontDescription& font_description,
const AtomicString& family_name) {
auto it = typeface_cache_.find(family_name);
if (it != typeface_cache_.end()) {
const TypefaceAsset* cache_asset = it->value.get();
return cache_asset ? cache_asset->typeface.get() : nullptr;
}
auto family_iter = font_family_map_.find(family_name);
if (family_iter == font_family_map_.end())
return nullptr;
String font_asset_path = font_asset_path_map_.get(family_name);
if (font_asset_path.isEmpty())
const std::vector<FlutterFontAttributes>& fonts = family_iter->value;
if (fonts.empty())
return nullptr;
std::vector<FlutterFontAttributes>::const_iterator font_iter;
if (fonts.size() == 1) {
font_iter = fonts.begin();
} else {
font_iter = std::min_element(fonts.begin(), fonts.end(),
FontMatcher(font_description));
}
const std::string& asset_path = font_iter->asset_path;
auto typeface_iter = typeface_cache_.find(asset_path);
if (typeface_iter != typeface_cache_.end()) {
const TypefaceAsset* cache_asset = typeface_iter->second.get();
return cache_asset ? cache_asset->typeface.get() : nullptr;
}
std::unique_ptr<TypefaceAsset> typeface_asset(new TypefaceAsset);
if (!zip_asset_bundle_->GetAsBuffer(font_asset_path.toUTF8(),
if (!zip_asset_bundle_->GetAsBuffer(asset_path,
&typeface_asset->data)) {
typeface_cache_.set(family_name, nullptr);
typeface_cache_.insert(std::make_pair(asset_path, nullptr));
return nullptr;
}
......@@ -163,12 +258,14 @@ SkTypeface* FlutterFontSelector::getTypefaceAsset(
typeface_asset->typeface = adoptRef(
font_mgr->createFromStream(typeface_stream));
if (typeface_asset->typeface == nullptr) {
typeface_cache_.set(family_name, nullptr);
typeface_cache_.insert(std::make_pair(asset_path, nullptr));
return nullptr;
}
SkTypeface* result = typeface_asset->typeface.get();
typeface_cache_.set(family_name, adoptPtr(typeface_asset.release()));
typeface_cache_.insert(std::make_pair(
asset_path, std::move(typeface_asset)));
return result;
}
......
......@@ -5,6 +5,7 @@
#ifndef SKY_SHELL_UI_FLUTTER_FONT_SELECTOR_H_
#define SKY_SHELL_UI_FLUTTER_FONT_SELECTOR_H_
#include <unordered_map>
#include <vector>
#include "sky/engine/platform/fonts/FontCacheKey.h"
......@@ -24,6 +25,8 @@ namespace shell {
// loaded from the FLX.
class FlutterFontSelector : public blink::FontSelector {
public:
struct FlutterFontAttributes;
~FlutterFontSelector() override;
static void install(
......@@ -42,24 +45,22 @@ class FlutterFontSelector : public blink::FontSelector {
void fontCacheInvalidated() override;
private:
// A Skia typeface along with a buffer holding the raw typeface asset data.
struct TypefaceAsset {
TypefaceAsset();
~TypefaceAsset();
RefPtr<SkTypeface> typeface;
std::vector<uint8_t> data;
};
struct TypefaceAsset;
FlutterFontSelector(
const scoped_refptr<mojo::asset_bundle::ZipAssetBundle>& zip_asset_bundle);
void parseFontManifest();
SkTypeface* getTypefaceAsset(const AtomicString& family_name);
SkTypeface* getTypefaceAsset(const blink::FontDescription& font_description,
const AtomicString& family_name);
scoped_refptr<mojo::asset_bundle::ZipAssetBundle> zip_asset_bundle_;
HashMap<AtomicString, String> font_asset_path_map_;
HashMap<AtomicString, OwnPtr<TypefaceAsset>> typeface_cache_;
HashMap<AtomicString, std::vector<FlutterFontAttributes>> font_family_map_;
std::unordered_map<std::string, std::unique_ptr<TypefaceAsset>>
typeface_cache_;
typedef HashMap<blink::FontCacheKey, RefPtr<blink::SimpleFontData>,
blink::FontCacheKeyHash, blink::FontCacheKeyTraits>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册