1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "font_collection.h"
17
18 #include "convert.h"
19 #include "custom_symbol_config.h"
20 #include "texgine/src/font_descriptor_mgr.h"
21 #include "txt/platform.h"
22 #include "text/typeface.h"
23 #include "utils/text_log.h"
24 #include "utils/text_trace.h"
25
26 namespace OHOS {
27 namespace Rosen {
28 FontCollection::FontCallback FontCollection::loadFontStartCallback_ {};
29 FontCollection::FontCallback FontCollection::loadFontFinishCallback_ {};
30 FontCollection::FontCallback FontCollection::unloadFontStartCallback_ {};
31 FontCollection::FontCallback FontCollection::unloadFontFinishCallback_ {};
32
Create()33 std::shared_ptr<FontCollection> FontCollection::Create()
34 {
35 static std::shared_ptr<FontCollection> instance = std::make_shared<AdapterTxt::FontCollection>();
36 return instance;
37 }
38
From(std::shared_ptr<txt::FontCollection> fontCollection)39 std::shared_ptr<FontCollection> FontCollection::From(std::shared_ptr<txt::FontCollection> fontCollection)
40 {
41 return std::make_shared<AdapterTxt::FontCollection>(fontCollection);
42 }
43
44 namespace AdapterTxt {
FontCollection(std::shared_ptr<txt::FontCollection> fontCollection)45 FontCollection::FontCollection(std::shared_ptr<txt::FontCollection> fontCollection)
46 : fontCollection_(fontCollection), dfmanager_(Drawing::FontMgr::CreateDynamicFontMgr())
47 {
48 if (fontCollection_ == nullptr) {
49 fontCollection_ = std::make_shared<txt::FontCollection>();
50 }
51 fontCollection_->SetupDefaultFontManager();
52 fontCollection_->SetDynamicFontManager(dfmanager_);
53 }
54
Get()55 std::shared_ptr<txt::FontCollection> FontCollection::Get()
56 {
57 return fontCollection_;
58 }
59
~FontCollection()60 FontCollection::~FontCollection()
61 {
62 if (Drawing::Typeface::GetTypefaceUnRegisterCallBack() == nullptr) {
63 return;
64 }
65
66 std::unique_lock<std::shared_mutex> lock(mutex_);
67 for (const auto& ta : typefaceSet_) {
68 Drawing::Typeface::GetTypefaceUnRegisterCallBack()(ta.GetTypeface());
69 }
70 for (const auto& family : familyNames_) {
71 FontDescriptorMgrInstance.DeleteDynamicTypefaceFromCache(family.second);
72 }
73 typefaceSet_.clear();
74 familyNames_.clear();
75 }
76
DisableFallback()77 void FontCollection::DisableFallback()
78 {
79 fontCollection_->DisableFontFallback();
80 }
81
DisableSystemFont()82 void FontCollection::DisableSystemFont()
83 {
84 fontCollection_->SetDefaultFontManager(nullptr);
85 }
86
GetFontMgr()87 std::shared_ptr<Drawing::FontMgr> FontCollection::GetFontMgr()
88 {
89 return dfmanager_;
90 }
91
RegisterTypeface(const TypefaceWithAlias & ta)92 RegisterError FontCollection::RegisterTypeface(const TypefaceWithAlias& ta)
93 {
94 if (ta.GetTypeface() == nullptr || Drawing::Typeface::GetTypefaceRegisterCallBack() == nullptr) {
95 return RegisterError::INVALID_INPUT;
96 }
97
98 std::unique_lock<std::shared_mutex> lock(mutex_);
99 if (typefaceSet_.count(ta)) {
100 TEXT_LOGI_LIMIT3_MIN(
101 "Find same typeface, family name: %{public}s, hash: %{public}u", ta.GetAlias().c_str(), ta.GetHash());
102 return RegisterError::ALREADY_EXIST;
103 }
104 if (!Drawing::Typeface::GetTypefaceRegisterCallBack()(ta.GetTypeface())) {
105 return RegisterError::REGISTER_FAILED;
106 }
107 TEXT_LOGI("Succeed in registering typeface, family name: %{public}s, hash: %{public}u", ta.GetAlias().c_str(),
108 ta.GetHash());
109 typefaceSet_.insert(ta);
110 return RegisterError::SUCCESS;
111 }
112
LoadFont(const std::string & familyName,const uint8_t * data,size_t datalen)113 std::shared_ptr<Drawing::Typeface> FontCollection::LoadFont(
114 const std::string& familyName, const uint8_t* data, size_t datalen)
115 {
116 TEXT_TRACE_FUNC();
117 std::shared_ptr<Drawing::Typeface> typeface(dfmanager_->LoadDynamicFont(familyName, data, datalen));
118 if (typeface == nullptr) {
119 TEXT_LOGE("Failed to load font %{public}s", familyName.c_str());
120 return nullptr;
121 }
122 TypefaceWithAlias ta(familyName, typeface);
123 FontCallbackGuard cb(this, ta.GetAlias(), loadFontStartCallback_, loadFontFinishCallback_);
124 RegisterError err = RegisterTypeface(ta);
125 if (err != RegisterError::SUCCESS && err != RegisterError::ALREADY_EXIST) {
126 TEXT_LOGE("Failed to register typeface %{public}s", ta.GetAlias().c_str());
127 return nullptr;
128 }
129 FontDescriptorMgrInstance.CacheDynamicTypeface(typeface, ta.GetAlias());
130 familyNames_.emplace(ta.GetHash(), ta.GetAlias());
131 fontCollection_->ClearFontFamilyCache();
132 return typeface;
133 }
134
LoadSymbolFont(const std::string & familyName,const uint8_t * data,size_t datalen)135 LoadSymbolErrorCode FontCollection::LoadSymbolFont(const std::string& familyName, const uint8_t* data, size_t datalen)
136 {
137 TEXT_TRACE_FUNC();
138 std::shared_ptr<Drawing::Typeface> typeface(dfmanager_->LoadDynamicFont(familyName, data, datalen));
139 if (typeface == nullptr) {
140 return LoadSymbolErrorCode::LOAD_FAILED;
141 }
142 std::unique_lock<std::shared_mutex> lock(mutex_);
143 TypefaceWithAlias ta(familyName, typeface);
144 FontCallbackGuard cb(this, familyName, loadFontStartCallback_, loadFontFinishCallback_);
145 if (typefaceSet_.count(ta)) {
146 return LoadSymbolErrorCode::SUCCESS;
147 }
148 typefaceSet_.insert(ta);
149 return LoadSymbolErrorCode::SUCCESS;
150 }
151
LoadSymbolJson(const std::string & familyName,const uint8_t * data,size_t datalen)152 LoadSymbolErrorCode FontCollection::LoadSymbolJson(const std::string& familyName, const uint8_t* data, size_t datalen)
153 {
154 TEXT_TRACE_FUNC();
155 return OHOS::Rosen::Symbol::CustomSymbolConfig::GetInstance()->ParseConfig(familyName, data, datalen);
156 }
157
CreateTypeface(const uint8_t * data,size_t datalen)158 static std::shared_ptr<Drawing::Typeface> CreateTypeface(const uint8_t *data, size_t datalen)
159 {
160 if (datalen != 0 && data != nullptr) {
161 auto stream = std::make_unique<Drawing::MemoryStream>(data, datalen, true);
162 return Drawing::Typeface::MakeFromStream(std::move(stream));
163 }
164 return nullptr;
165 }
166
LoadThemeFont(const std::string & familyName,const uint8_t * data,size_t datalen)167 std::shared_ptr<Drawing::Typeface> FontCollection::LoadThemeFont(
168 const std::string& familyName, const uint8_t* data, size_t datalen)
169 {
170 TEXT_TRACE_FUNC();
171 auto res = LoadThemeFont(familyName, { { data, datalen } });
172 return res.empty() ? nullptr : res[0];
173 }
174
LoadThemeFont(const std::string & familyName,const std::vector<std::pair<const uint8_t *,size_t>> & data)175 std::vector<std::shared_ptr<Drawing::Typeface>> FontCollection::LoadThemeFont(
176 const std::string& familyName, const std::vector<std::pair<const uint8_t*, size_t>>& data)
177 {
178 if (familyName.empty()) {
179 ClearThemeFont();
180 return {};
181 }
182
183 std::vector<std::shared_ptr<Drawing::Typeface>> res;
184 size_t index = 0;
185 for (size_t i = 0; i < data.size(); i += 1) {
186 std::string themeFamily = SPText::DefaultFamilyNameMgr::GetInstance().GenerateThemeFamilyName(index);
187 auto face = CreateTypeface(data[i].first, data[i].second);
188 TypefaceWithAlias ta(themeFamily, face);
189 RegisterError err = RegisterTypeface(ta);
190 if (err == RegisterError::ALREADY_EXIST) {
191 res.emplace_back(face);
192 continue;
193 } else if (err != RegisterError::SUCCESS) {
194 TEXT_LOGE("Failed to load font %{public}s", familyName.c_str());
195 continue;
196 }
197 index += 1;
198 res.emplace_back(face);
199 dfmanager_->LoadThemeFont(themeFamily, face);
200 }
201 SPText::DefaultFamilyNameMgr::GetInstance().ModifyThemeFontFamilies(res.size());
202 fontCollection_->ClearFontFamilyCache();
203 fontCollection_->UpdateDefaultFamilies();
204 return res;
205 }
206
ClearThemeFont()207 void FontCollection::ClearThemeFont()
208 {
209 std::unique_lock lock(mutex_);
210 for (const auto& themeFamily : SPText::DefaultFamilyNameMgr::GetInstance().GetThemeFontFamilies()) {
211 std::shared_ptr<Drawing::Typeface> face(dfmanager_->MatchFamilyStyle(themeFamily.c_str(), {}));
212 TypefaceWithAlias ta(themeFamily, face);
213 typefaceSet_.erase(ta);
214 dfmanager_->LoadThemeFont("", themeFamily, nullptr, 0);
215 }
216 fontCollection_->ClearFontFamilyCache();
217 SPText::DefaultFamilyNameMgr::GetInstance().ModifyThemeFontFamilies(0);
218 }
219
ClearCaches()220 void FontCollection::ClearCaches()
221 {
222 fontCollection_->ClearFontFamilyCache();
223 }
224
UnloadFont(const std::string & familyName)225 bool FontCollection::UnloadFont(const std::string& familyName)
226 {
227 if (Drawing::Typeface::GetTypefaceUnRegisterCallBack() == nullptr ||
228 SPText::DefaultFamilyNameMgr::IsThemeFontFamily(familyName) || familyName.empty()) {
229 TEXT_LOGE("Failed to unload font: %{public}s", familyName.c_str());
230 return false;
231 }
232
233 std::shared_lock readLock(mutex_);
234 if (std::none_of(typefaceSet_.begin(), typefaceSet_.end(),
235 [&familyName](const auto& ta) { return ta.GetAlias() == familyName; })) {
236 TEXT_LOGE("Unload a font which is not loaded: %{public}s", familyName.c_str());
237 return true;
238 }
239 readLock.unlock();
240
241 FontCallbackGuard cb(this, familyName, unloadFontStartCallback_, unloadFontFinishCallback_);
242 std::unique_lock<std::shared_mutex> lock(mutex_);
243 for (auto it = typefaceSet_.begin(); it != typefaceSet_.end();) {
244 if (it->GetAlias() == familyName) {
245 dfmanager_->LoadDynamicFont(familyName, nullptr, 0);
246 FontDescriptorMgrInstance.DeleteDynamicTypefaceFromCache(familyName);
247 ClearCaches();
248 Drawing::Typeface::GetTypefaceUnRegisterCallBack()(it->GetTypeface());
249 familyNames_.erase(it->GetHash());
250 typefaceSet_.erase(it++);
251 } else {
252 ++it;
253 }
254 }
255
256 return true;
257 }
258
FontCallbackGuard(const FontCollection * fc,const std::string & familyName,const FontCallback & begin,const FontCallback & end)259 FontCollection::FontCallbackGuard::FontCallbackGuard(
260 const FontCollection* fc, const std::string& familyName, const FontCallback& begin, const FontCallback& end)
261 : fc_(fc), familyName_(familyName), begin_(begin), end_(end)
262 {
263 begin_.ExecuteCallback(fc_, familyName_);
264 }
265
~FontCallbackGuard()266 FontCollection::FontCallbackGuard::~FontCallbackGuard()
267 {
268 end_.ExecuteCallback(fc_, familyName_);
269 }
270
TypefaceWithAlias(const std::string & alias,const std::shared_ptr<Drawing::Typeface> & typeface)271 TypefaceWithAlias::TypefaceWithAlias(const std::string& alias, const std::shared_ptr<Drawing::Typeface>& typeface)
272 : alias_(alias), typeface_(typeface)
273 {
274 if (alias.empty() && typeface != nullptr) {
275 alias_ = typeface->GetFamilyName();
276 }
277 }
278
GetHash() const279 uint32_t TypefaceWithAlias::GetHash() const
280 {
281 if (hash_ != 0) {
282 return hash_;
283 }
284 hash_ = Hasher()(*this);
285 return hash_;
286 }
287
operator ()(const TypefaceWithAlias & ta) const288 uint32_t TypefaceWithAlias::Hasher::operator()(const TypefaceWithAlias& ta) const
289 {
290 uint32_t hashS = static_cast<uint32_t>(std::hash<std::string>()(ta.alias_));
291 uint32_t hashT = ta.typeface_ == nullptr ? 0 : ta.typeface_->GetHash();
292 ta.hash_ = static_cast<uint32_t>(std::hash<uint32_t>()(hashS ^ hashT));
293 return ta.hash_;
294 }
295
GetTypeface() const296 const std::shared_ptr<Drawing::Typeface>& TypefaceWithAlias::GetTypeface() const
297 {
298 return typeface_;
299 }
300
GetAlias() const301 const std::string& TypefaceWithAlias::GetAlias() const
302 {
303 return alias_;
304 }
305
operator ==(const TypefaceWithAlias & other) const306 bool TypefaceWithAlias::operator==(const TypefaceWithAlias& other) const
307 {
308 return other.alias_ == this->alias_ && other.GetHash() == this->GetHash();
309 }
310 } // namespace AdapterTxt
311
RegisterLoadFontStartCallback(FontCallbackType cb)312 void FontCollection::RegisterLoadFontStartCallback(FontCallbackType cb)
313 {
314 loadFontStartCallback_.AddCallback(cb);
315 }
316
RegisterUnloadFontStartCallback(FontCallbackType cb)317 void FontCollection::RegisterUnloadFontStartCallback(FontCallbackType cb)
318 {
319 unloadFontStartCallback_.AddCallback(cb);
320 }
321
RegisterLoadFontFinishCallback(FontCallbackType cb)322 void FontCollection::RegisterLoadFontFinishCallback(FontCallbackType cb)
323 {
324 loadFontFinishCallback_.AddCallback(cb);
325 }
326
RegisterUnloadFontFinishCallback(FontCallbackType cb)327 void FontCollection::RegisterUnloadFontFinishCallback(FontCallbackType cb)
328 {
329 unloadFontFinishCallback_.AddCallback(cb);
330 }
331
AddCallback(FontCallbackType cb)332 void FontCollection::FontCallback::AddCallback(FontCallbackType cb)
333 {
334 std::lock_guard lock(mutex_);
335 if (cb != nullptr) {
336 callback_.emplace(cb);
337 } else {
338 TEXT_LOGE("Failed to register callback, cb is nullptr");
339 }
340 }
341
ExecuteCallback(const FontCollection * fc,const std::string & family) const342 void FontCollection::FontCallback::ExecuteCallback(const FontCollection* fc, const std::string& family) const
343 {
344 std::lock_guard lock(mutex_);
345 for (auto& cb : callback_) {
346 cb(fc, family);
347 }
348 }
349 } // namespace Rosen
350 } // namespace OHOS
351