asset_font_selector.cc 8.5 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/zip_asset_store.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 13
#include "lib/ftl/arraysize.h"
#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 38 39 40 41 42 43 44 45 46
  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;
47 48 49
  return (weight_index < arraysize(kFontWeightValue))
             ? kFontWeightValue[weight_index]
             : kFontWeightNormal;
50 51 52 53 54
}

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

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

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

81 82 83
void AssetFontSelector::Install(ftl::RefPtr<ZipAssetStore> asset_store) {
  RefPtr<AssetFontSelector> font_selector =
      adoptRef(new AssetFontSelector(std::move(asset_store)));
J
Jason Simmons 已提交
84
  font_selector->parseFontManifest();
85
  UIDartState::Current()->set_font_selector(font_selector);
J
Jason Simmons 已提交
86 87
}

88
AssetFontSelector::AssetFontSelector(ftl::RefPtr<ZipAssetStore> asset_store)
89
    : asset_store_(std::move(asset_store)) {}
J
Jason Simmons 已提交
90

91
AssetFontSelector::~AssetFontSelector() {}
J
Jason Simmons 已提交
92

93
AssetFontSelector::TypefaceAsset::TypefaceAsset() {}
J
Jason Simmons 已提交
94

95
AssetFontSelector::TypefaceAsset::~TypefaceAsset() {}
96

97
AssetFontSelector::FlutterFontAttributes::FlutterFontAttributes(
98 99 100
    const std::string& path)
    : asset_path(path),
      weight(kFontWeightNormal),
101
      style(FontStyle::FontStyleNormal) {}
102

103
AssetFontSelector::FlutterFontAttributes::~FlutterFontAttributes() {}
104

105
void AssetFontSelector::parseFontManifest() {
J
Jason Simmons 已提交
106
  std::vector<uint8_t> font_manifest_data;
107
  if (!asset_store_->GetAsBuffer(kFontManifestAssetPath, &font_manifest_data))
J
Jason Simmons 已提交
108 109
    return;

110 111 112 113 114
  rapidjson::Document document;
  document.Parse(reinterpret_cast<const char*>(font_manifest_data.data()),
                 font_manifest_data.size());

  if (document.HasParseError())
J
Jason Simmons 已提交
115 116
    return;

117
  if (!document.IsArray())
J
Jason Simmons 已提交
118 119
    return;

120 121
  for (auto& family : document.GetArray()) {
    if (!family.IsObject())
J
Jason Simmons 已提交
122
      continue;
123 124 125

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

128 129
    auto font_list = family.FindMember("fonts");
    if (font_list == family.MemberEnd() || !font_list->value.IsArray())
J
Jason Simmons 已提交
130 131
      continue;

132 133
    AtomicString family_key =
        AtomicString::fromUTF8(family_name->value.GetString());
134 135
    auto set_result =
        font_family_map_.set(family_key, std::vector<FlutterFontAttributes>());
136 137
    std::vector<FlutterFontAttributes>& family_assets =
        set_result.storedValue->value;
J
Jason Simmons 已提交
138

139 140
    for (auto& list_entry : font_list->value.GetArray()) {
      if (!list_entry.IsObject())
141 142
        continue;

143 144
      auto asset_path = list_entry.FindMember("asset");
      if (asset_path == list_entry.MemberEnd() || !asset_path->value.IsString())
145 146
        continue;

147 148 149 150 151
      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();
152

153 154 155
      auto style = list_entry.FindMember("style");
      if (style != list_entry.MemberEnd() && style->value.IsString()) {
        if (std::string(style->value.GetString()) == "italic")
156 157
          attributes.style = FontStyle::FontStyleItalic;
      }
J
Jason Simmons 已提交
158

159 160
      family_assets.push_back(attributes);
    }
J
Jason Simmons 已提交
161 162 163
  }
}

164
PassRefPtr<FontData> AssetFontSelector::getFontData(
J
Jason Simmons 已提交
165 166 167 168 169 170 171
    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) {
172 173
    sk_sp<SkTypeface> typeface =
        getTypefaceAsset(font_description, family_name);
A
Adam Barth 已提交
174
    if (!typeface)
J
Jason Simmons 已提交
175 176
      return nullptr;

177 178 179
    bool synthetic_bold =
        (font_description.weight() >= FontWeight600 && !typeface->isBold()) ||
        font_description.isSyntheticBold();
J
Jason Simmons 已提交
180 181 182
    bool synthetic_italic =
        (font_description.style() && !typeface->isItalic()) ||
        font_description.isSyntheticItalic();
183 184 185 186 187
    FontPlatformData platform_data(typeface, family_name.utf8().data(),
                                   font_description.effectiveFontSize(),
                                   synthetic_bold, synthetic_italic,
                                   font_description.orientation(),
                                   font_description.useSubpixelPositioning());
J
Jason Simmons 已提交
188 189 190 191 192 193 194 195

    font_data = SimpleFontData::create(platform_data);
    font_platform_data_cache_.set(key, font_data);
  }

  return font_data;
}

196
sk_sp<SkTypeface> AssetFontSelector::getTypefaceAsset(
197
    const FontDescription& font_description,
J
Jason Simmons 已提交
198
    const AtomicString& family_name) {
199 200 201
  auto family_iter = font_family_map_.find(family_name);
  if (family_iter == font_family_map_.end())
    return nullptr;
J
Jason Simmons 已提交
202

203 204
  const std::vector<FlutterFontAttributes>& fonts = family_iter->value;
  if (fonts.empty())
J
Jason Simmons 已提交
205 206
    return nullptr;

207 208 209 210 211 212 213 214 215 216 217 218
  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 已提交
219
    return cache_asset ? cache_asset->typeface : nullptr;
220 221
  }

J
Jason Simmons 已提交
222
  std::unique_ptr<TypefaceAsset> typeface_asset(new TypefaceAsset);
223
  if (!asset_store_->GetAsBuffer(asset_path, &typeface_asset->data)) {
224
    typeface_cache_.insert(std::make_pair(asset_path, nullptr));
J
Jason Simmons 已提交
225 226 227 228 229 230
    return nullptr;
  }

  SkAutoTUnref<SkFontMgr> font_mgr(SkFontMgr::RefDefault());
  SkMemoryStream* typeface_stream = new SkMemoryStream(
      typeface_asset->data.data(), typeface_asset->data.size());
231 232
  typeface_asset->typeface =
      sk_sp<SkTypeface>(font_mgr->createFromStream(typeface_stream));
J
Jason Simmons 已提交
233
  if (typeface_asset->typeface == nullptr) {
234
    typeface_cache_.insert(std::make_pair(asset_path, nullptr));
J
Jason Simmons 已提交
235 236 237
    return nullptr;
  }

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

J
Jason Simmons 已提交
241 242 243
  return result;
}

244 245 246
void AssetFontSelector::willUseFontData(const FontDescription& font_description,
                                        const AtomicString& family,
                                        UChar32 character) {}
J
Jason Simmons 已提交
247

248
unsigned AssetFontSelector::version() const {
J
Jason Simmons 已提交
249 250 251
  return 0;
}

252
void AssetFontSelector::fontCacheInvalidated() {}
J
Jason Simmons 已提交
253

254
}  // namespace blink