diff --git a/sky/shell/ui/flutter_font_selector.cc b/sky/shell/ui/flutter_font_selector.cc index c3efbcacb4a9d330daa344cd9601aaeb4c9a7116..0e6a11a0abf0879b63f0498cf4bcf6913909892e 100644 --- a/sky/shell/ui/flutter_font_selector.cc +++ b/sky/shell/ui/flutter_font_selector.cc @@ -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 typeface; + std::vector 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& zip_asset_bundle) { RefPtr 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 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()); + std::vector& 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 FlutterFontSelector::getFontData( RefPtr 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 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& fonts = family_iter->value; + if (fonts.empty()) return nullptr; + std::vector::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 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; } diff --git a/sky/shell/ui/flutter_font_selector.h b/sky/shell/ui/flutter_font_selector.h index 015dd3978ce865e9691368b3eb55784a7869db25..a8b3c475f2fced220f32b0df7730602ee910f5db 100644 --- a/sky/shell/ui/flutter_font_selector.h +++ b/sky/shell/ui/flutter_font_selector.h @@ -5,6 +5,7 @@ #ifndef SKY_SHELL_UI_FLUTTER_FONT_SELECTOR_H_ #define SKY_SHELL_UI_FLUTTER_FONT_SELECTOR_H_ +#include #include #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 typeface; - std::vector data; - }; + struct TypefaceAsset; FlutterFontSelector( const scoped_refptr& zip_asset_bundle); void parseFontManifest(); - SkTypeface* getTypefaceAsset(const AtomicString& family_name); + + SkTypeface* getTypefaceAsset(const blink::FontDescription& font_description, + const AtomicString& family_name); scoped_refptr zip_asset_bundle_; - HashMap font_asset_path_map_; - HashMap> typeface_cache_; + HashMap> font_family_map_; + + std::unordered_map> + typeface_cache_; typedef HashMap, blink::FontCacheKeyHash, blink::FontCacheKeyTraits>