1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "flutter/lib/ui/text/font_collection.h"
6
7#include <mutex>
8
9#include "flutter/lib/ui/text/asset_manager_font_provider.h"
10#include "flutter/lib/ui/ui_dart_state.h"
11#include "flutter/lib/ui/window/platform_configuration.h"
12#include "flutter/runtime/test_font_data.h"
13#include "rapidjson/document.h"
14#include "rapidjson/rapidjson.h"
15#include "third_party/skia/include/core/SkFontMgr.h"
16#include "third_party/skia/include/core/SkGraphics.h"
17#include "third_party/skia/include/core/SkStream.h"
18#include "third_party/skia/include/core/SkTypeface.h"
19#include "third_party/tonic/dart_args.h"
20#include "third_party/tonic/dart_library_natives.h"
21#include "third_party/tonic/logging/dart_invoke.h"
22#include "third_party/tonic/typed_data/typed_list.h"
23#include "txt/asset_font_manager.h"
24#include "txt/test_font_manager.h"
25
26namespace flutter {
27
28namespace {
29
30void LoadFontFromList(tonic::Uint8List& font_data, // NOLINT
31 Dart_Handle callback,
32 std::string family_name) {
33 FontCollection& font_collection = UIDartState::Current()
34 ->platform_configuration()
35 ->client()
36 ->GetFontCollection();
37 font_collection.LoadFontFromList(font_data.data(), font_data.num_elements(),
38 family_name);
39 font_data.Release();
40 tonic::DartInvoke(callback, {tonic::ToDart(0)});
41}
42
43void _LoadFontFromList(Dart_NativeArguments args) {
44 UIDartState::ThrowIfUIOperationsProhibited();
45 tonic::DartCallStatic(LoadFontFromList, args);
46}
47
48} // namespace
49
50FontCollection::FontCollection()
51 : collection_(std::make_shared<txt::FontCollection>()) {
52 dynamic_font_manager_ = sk_make_sp<txt::DynamicFontManager>();
53 collection_->SetDynamicFontManager(dynamic_font_manager_);
54}
55
56FontCollection::~FontCollection() {
57 collection_.reset();
58 SkGraphics::PurgeFontCache();
59}
60
61void FontCollection::RegisterNatives(tonic::DartLibraryNatives* natives) {
62 natives->Register({
63 {"loadFontFromList", _LoadFontFromList, 3, true},
64 });
65}
66
67std::shared_ptr<txt::FontCollection> FontCollection::GetFontCollection() const {
68 return collection_;
69}
70
71void FontCollection::SetupDefaultFontManager() {
72 collection_->SetupDefaultFontManager();
73}
74
75void FontCollection::RegisterFonts(
76 std::shared_ptr<AssetManager> asset_manager) {
77 std::unique_ptr<fml::Mapping> manifest_mapping =
78 asset_manager->GetAsMapping("FontManifest.json");
79 if (manifest_mapping == nullptr) {
80 FML_DLOG(WARNING) << "Could not find the font manifest in the asset store.";
81 return;
82 }
83
84 rapidjson::Document document;
85 static_assert(sizeof(decltype(document)::Ch) == sizeof(uint8_t), "");
86 document.Parse(reinterpret_cast<const decltype(document)::Ch*>(
87 manifest_mapping->GetMapping()),
88 manifest_mapping->GetSize());
89
90 if (document.HasParseError()) {
91 FML_DLOG(WARNING) << "Error parsing the font manifest in the asset store.";
92 return;
93 }
94
95 // Structure described in https://flutter.io/custom-fonts/
96
97 if (!document.IsArray()) {
98 return;
99 }
100
101 auto font_provider =
102 std::make_unique<AssetManagerFontProvider>(asset_manager);
103
104 for (const auto& family : document.GetArray()) {
105 auto family_name = family.FindMember("family");
106 if (family_name == family.MemberEnd() || !family_name->value.IsString()) {
107 continue;
108 }
109
110 auto family_fonts = family.FindMember("fonts");
111 if (family_fonts == family.MemberEnd() || !family_fonts->value.IsArray()) {
112 continue;
113 }
114
115 for (const auto& family_font : family_fonts->value.GetArray()) {
116 if (!family_font.IsObject()) {
117 continue;
118 }
119
120 auto font_asset = family_font.FindMember("asset");
121 if (font_asset == family_font.MemberEnd() ||
122 !font_asset->value.IsString()) {
123 continue;
124 }
125
126 // TODO(chinmaygarde): Handle weights and styles.
127 font_provider->RegisterAsset(family_name->value.GetString(),
128 font_asset->value.GetString());
129 }
130 }
131
132 collection_->SetAssetFontManager(
133 sk_make_sp<txt::AssetFontManager>(std::move(font_provider)));
134}
135
136void FontCollection::RegisterTestFonts() {
137 std::vector<sk_sp<SkTypeface>> test_typefaces;
138 std::vector<std::unique_ptr<SkStreamAsset>> font_data = GetTestFontData();
139 for (auto& font : font_data) {
140 test_typefaces.push_back(SkTypeface::MakeFromStream(std::move(font)));
141 }
142
143 std::unique_ptr<txt::TypefaceFontAssetProvider> font_provider =
144 std::make_unique<txt::TypefaceFontAssetProvider>();
145
146 size_t index = 0;
147 std::vector<std::string> names = GetTestFontFamilyNames();
148 for (sk_sp<SkTypeface> typeface : test_typefaces) {
149 font_provider->RegisterTypeface(std::move(typeface), names[index]);
150 index++;
151 }
152
153 collection_->SetTestFontManager(
154 sk_make_sp<txt::TestFontManager>(std::move(font_provider), names));
155
156 collection_->DisableFontFallback();
157}
158
159void FontCollection::LoadFontFromList(const uint8_t* font_data,
160 int length,
161 std::string family_name) {
162 std::unique_ptr<SkStreamAsset> font_stream =
163 std::make_unique<SkMemoryStream>(font_data, length, true);
164 sk_sp<SkTypeface> typeface =
165 SkTypeface::MakeFromStream(std::move(font_stream));
166 txt::TypefaceFontAssetProvider& font_provider =
167 dynamic_font_manager_->font_provider();
168 if (family_name.empty()) {
169 font_provider.RegisterTypeface(typeface);
170 } else {
171 font_provider.RegisterTypeface(typeface, family_name);
172 }
173 collection_->ClearFontFamilyCache();
174}
175
176} // namespace flutter
177