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 | |
26 | namespace flutter { |
27 | |
28 | namespace { |
29 | |
30 | void 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 | |
43 | void _LoadFontFromList(Dart_NativeArguments args) { |
44 | UIDartState::ThrowIfUIOperationsProhibited(); |
45 | tonic::DartCallStatic(LoadFontFromList, args); |
46 | } |
47 | |
48 | } // namespace |
49 | |
50 | FontCollection::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 | |
56 | FontCollection::~FontCollection() { |
57 | collection_.reset(); |
58 | SkGraphics::PurgeFontCache(); |
59 | } |
60 | |
61 | void FontCollection::RegisterNatives(tonic::DartLibraryNatives* natives) { |
62 | natives->Register({ |
63 | {"loadFontFromList" , _LoadFontFromList, 3, true}, |
64 | }); |
65 | } |
66 | |
67 | std::shared_ptr<txt::FontCollection> FontCollection::GetFontCollection() const { |
68 | return collection_; |
69 | } |
70 | |
71 | void FontCollection::SetupDefaultFontManager() { |
72 | collection_->SetupDefaultFontManager(); |
73 | } |
74 | |
75 | void 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 | |
136 | void 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 | |
159 | void 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 | |