asset_font_selector.cc 9.3 KB
Newer Older
J
Jason Simmons 已提交
1 2 3 4
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
#include "flutter/runtime/asset_font_selector.h"
6

7
#include "flutter/assets/directory_asset_bundle.h"
8
#include "flutter/lib/ui/ui_dart_state.h"
9 10 11
#include "flutter/sky/engine/platform/fonts/FontData.h"
#include "flutter/sky/engine/platform/fonts/FontFaceCreationParams.h"
#include "flutter/sky/engine/platform/fonts/SimpleFontData.h"
12
#include "lib/fxl/arraysize.h"
13
#include "third_party/rapidjson/rapidjson/document.h"
J
Jason Simmons 已提交
14 15 16 17
#include "third_party/skia/include/core/SkStream.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "third_party/skia/include/ports/SkFontMgr.h"

18
namespace blink {
J
Jason Simmons 已提交
19

20
// Style attributes of a Flutter font asset.
21
struct AssetFontSelector::FlutterFontAttributes {
22 23 24 25 26 27 28 29
  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.
30
struct AssetFontSelector::TypefaceAsset {
31 32
  TypefaceAsset();
  ~TypefaceAsset();
A
Adam Barth 已提交
33
  sk_sp<SkTypeface> typeface;
34 35 36 37
  std::vector<uint8_t> data;
};

namespace {
38

39 40 41 42 43 44 45 46 47
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;
48 49 50
  return (weight_index < arraysize(kFontWeightValue))
             ? kFontWeightValue[weight_index]
             : kFontWeightNormal;
51 52 53 54 55
}

// Compares fonts within a family to determine which one most closely matches
// a FontDescription.
struct FontMatcher {
56
  using FlutterFontAttributes = AssetFontSelector::FlutterFontAttributes;
57 58 59

  FontMatcher(const FontDescription& description)
      : description_(description),
60
        target_weight_(getFontWeightValue(description.weight())) {}
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79

  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_;
};
80 81

}  // namespace
82

83 84
void AssetFontSelector::Install(
    fxl::RefPtr<AssetProvider> asset_provider) {
85
  RefPtr<AssetFontSelector> font_selector =
86
      adoptRef(new AssetFontSelector(std::move(asset_provider)));
J
Jason Simmons 已提交
87
  font_selector->parseFontManifest();
88
  UIDartState::Current()->set_font_selector(font_selector);
J
Jason Simmons 已提交
89 90
}

91 92 93 94 95 96 97 98 99 100 101 102 103
void AssetFontSelector::Install(fxl::RefPtr<ZipAssetStore> asset_store) {
  RefPtr<AssetFontSelector> font_selector =
      adoptRef(new AssetFontSelector(std::move(asset_store)));
  font_selector->parseFontManifest();
  UIDartState::Current()->set_font_selector(font_selector);
}

AssetFontSelector::AssetFontSelector(
    fxl::RefPtr<AssetProvider> asset_provider)
    : asset_provider_(std::move(asset_provider)) {}

AssetFontSelector::AssetFontSelector(fxl::RefPtr<ZipAssetStore> asset_store)
    : asset_store_(std::move(asset_store)) {}
104

105
AssetFontSelector::~AssetFontSelector() {}
J
Jason Simmons 已提交
106

107
AssetFontSelector::TypefaceAsset::TypefaceAsset() {}
J
Jason Simmons 已提交
108

109
AssetFontSelector::TypefaceAsset::~TypefaceAsset() {}
110

111
AssetFontSelector::FlutterFontAttributes::FlutterFontAttributes(
112 113 114
    const std::string& path)
    : asset_path(path),
      weight(kFontWeightNormal),
115
      style(FontStyle::FontStyleNormal) {}
116

117
AssetFontSelector::FlutterFontAttributes::~FlutterFontAttributes() {}
118

119
void AssetFontSelector::parseFontManifest() {
J
Jason Simmons 已提交
120
  std::vector<uint8_t> font_manifest_data;
121 122 123 124 125 126
  if (!asset_provider_ ||
      !asset_provider_->GetAsBuffer(kFontManifestAssetPath,
                                    &font_manifest_data)) {
    if (!asset_store_ ||
        !asset_store_->GetAsBuffer(kFontManifestAssetPath, &font_manifest_data))
      return;
127
  }
J
Jason Simmons 已提交
128

129 130 131 132 133
  rapidjson::Document document;
  document.Parse(reinterpret_cast<const char*>(font_manifest_data.data()),
                 font_manifest_data.size());

  if (document.HasParseError())
J
Jason Simmons 已提交
134 135
    return;

136
  if (!document.IsArray())
J
Jason Simmons 已提交
137 138
    return;

139 140
  for (auto& family : document.GetArray()) {
    if (!family.IsObject())
J
Jason Simmons 已提交
141
      continue;
142 143 144

    auto family_name = family.FindMember("family");
    if (family_name == family.MemberEnd() || !family_name->value.IsString())
J
Jason Simmons 已提交
145 146
      continue;

147 148
    auto font_list = family.FindMember("fonts");
    if (font_list == family.MemberEnd() || !font_list->value.IsArray())
J
Jason Simmons 已提交
149 150
      continue;

151 152
    AtomicString family_key =
        AtomicString::fromUTF8(family_name->value.GetString());
153 154
    auto set_result =
        font_family_map_.set(family_key, std::vector<FlutterFontAttributes>());
155 156
    std::vector<FlutterFontAttributes>& family_assets =
        set_result.storedValue->value;
J
Jason Simmons 已提交
157

158 159
    for (auto& list_entry : font_list->value.GetArray()) {
      if (!list_entry.IsObject())
160 161
        continue;

162 163
      auto asset_path = list_entry.FindMember("asset");
      if (asset_path == list_entry.MemberEnd() || !asset_path->value.IsString())
164 165
        continue;

166 167 168 169 170
      FlutterFontAttributes attributes(asset_path->value.GetString());

      auto weight = list_entry.FindMember("weight");
      if (weight != list_entry.MemberEnd() && weight->value.IsInt())
        attributes.weight = weight->value.GetInt();
171

172 173 174
      auto style = list_entry.FindMember("style");
      if (style != list_entry.MemberEnd() && style->value.IsString()) {
        if (std::string(style->value.GetString()) == "italic")
175 176
          attributes.style = FontStyle::FontStyleItalic;
      }
J
Jason Simmons 已提交
177

178 179
      family_assets.push_back(attributes);
    }
J
Jason Simmons 已提交
180 181 182
  }
}

183
PassRefPtr<FontData> AssetFontSelector::getFontData(
J
Jason Simmons 已提交
184 185 186 187 188 189 190
    const FontDescription& font_description,
    const AtomicString& family_name) {
  FontFaceCreationParams creationParams(family_name);
  FontCacheKey key = font_description.cacheKey(creationParams);
  RefPtr<SimpleFontData> font_data = font_platform_data_cache_.get(key);

  if (font_data == nullptr) {
191 192
    sk_sp<SkTypeface> typeface =
        getTypefaceAsset(font_description, family_name);
A
Adam Barth 已提交
193
    if (!typeface)
J
Jason Simmons 已提交
194 195
      return nullptr;

196 197 198
    bool synthetic_bold =
        (font_description.weight() >= FontWeight600 && !typeface->isBold()) ||
        font_description.isSyntheticBold();
J
Jason Simmons 已提交
199 200 201
    bool synthetic_italic =
        (font_description.style() && !typeface->isItalic()) ||
        font_description.isSyntheticItalic();
202 203 204 205 206
    FontPlatformData platform_data(typeface, family_name.utf8().data(),
                                   font_description.effectiveFontSize(),
                                   synthetic_bold, synthetic_italic,
                                   font_description.orientation(),
                                   font_description.useSubpixelPositioning());
J
Jason Simmons 已提交
207

208
    font_data = SimpleFontData::create(platform_data, CustomFontData::create());
J
Jason Simmons 已提交
209 210 211 212 213 214
    font_platform_data_cache_.set(key, font_data);
  }

  return font_data;
}

215
sk_sp<SkTypeface> AssetFontSelector::getTypefaceAsset(
216
    const FontDescription& font_description,
J
Jason Simmons 已提交
217
    const AtomicString& family_name) {
218 219 220
  auto family_iter = font_family_map_.find(family_name);
  if (family_iter == font_family_map_.end())
    return nullptr;
J
Jason Simmons 已提交
221

222 223
  const std::vector<FlutterFontAttributes>& fonts = family_iter->value;
  if (fonts.empty())
J
Jason Simmons 已提交
224 225
    return nullptr;

226 227 228 229 230 231 232 233 234 235 236 237
  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();
A
Adam Barth 已提交
238
    return cache_asset ? cache_asset->typeface : nullptr;
239 240
  }

J
Jason Simmons 已提交
241
  std::unique_ptr<TypefaceAsset> typeface_asset(new TypefaceAsset);
242 243 244 245 246 247 248
  if (!asset_provider_ || !asset_provider_->GetAsBuffer(
                              asset_path, &typeface_asset->data)) {
    if (!asset_store_ ||
        !asset_store_->GetAsBuffer(asset_path, &typeface_asset->data)) {
      typeface_cache_.insert(std::make_pair(asset_path, nullptr));
      return nullptr;
    }
J
Jason Simmons 已提交
249 250
  }

251
  sk_sp<SkFontMgr> font_mgr(SkFontMgr::RefDefault());
B
Brian Osman 已提交
252 253 254
  std::unique_ptr<SkStreamAsset> typeface_stream =
      std::make_unique<SkMemoryStream>(typeface_asset->data.data(),
                                       typeface_asset->data.size());
255
  typeface_asset->typeface =
B
Brian Osman 已提交
256
      font_mgr->makeFromStream(std::move(typeface_stream));
J
Jason Simmons 已提交
257
  if (typeface_asset->typeface == nullptr) {
258
    typeface_cache_.insert(std::make_pair(asset_path, nullptr));
J
Jason Simmons 已提交
259 260 261
    return nullptr;
  }

A
Adam Barth 已提交
262
  sk_sp<SkTypeface> result = typeface_asset->typeface;
263
  typeface_cache_.insert(std::make_pair(asset_path, std::move(typeface_asset)));
264

J
Jason Simmons 已提交
265 266 267
  return result;
}

268 269 270
void AssetFontSelector::willUseFontData(const FontDescription& font_description,
                                        const AtomicString& family,
                                        UChar32 character) {}
J
Jason Simmons 已提交
271

272
unsigned AssetFontSelector::version() const {
J
Jason Simmons 已提交
273 274 275
  return 0;
}

276
void AssetFontSelector::fontCacheInvalidated() {}
J
Jason Simmons 已提交
277

278
}  // namespace blink