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_descriptor_cache.h"
17
18 #include <algorithm>
19 #include <dirent.h>
20 #include <fcntl.h>
21 #include <fstream>
22 #include <sys/stat.h>
23 #include <unicode/brkiter.h>
24 #include <unistd.h>
25
26 #include "font_config.h"
27 #include "text/common_utils.h"
28 #include "utils/text_log.h"
29
30 #define INSTALL_FONT_CONFIG_FILE "/data/service/el1/public/for-all-app/fonts/install_fontconfig.json"
31
32 namespace OHOS::Rosen {
33 namespace {
34 constexpr uint32_t WEIGHT_400 = 400;
35 }
36
FontDescriptorCache()37 FontDescriptorCache::FontDescriptorCache() {}
38
~FontDescriptorCache()39 FontDescriptorCache::~FontDescriptorCache() {}
40
ClearFontFileCache()41 void FontDescriptorCache::ClearFontFileCache()
42 {
43 allFontDescriptor_.clear();
44 fontFamilyMap_.clear();
45 fullNameMap_.clear();
46 postScriptNameMap_.clear();
47 fontSubfamilyNameMap_.clear();
48 boldCache_.clear();
49 italicCache_.clear();
50 monoSpaceCache_.clear();
51 symbolicCache_.clear();
52 stylishFullNameMap_.clear();
53 }
54
ParserSystemFonts()55 void FontDescriptorCache::ParserSystemFonts()
56 {
57 for (auto& item : parser_.GetSystemFonts()) {
58 FontDescriptorScatter(item);
59 }
60 Dump();
61 }
62
ParserStylishFonts()63 void FontDescriptorCache::ParserStylishFonts()
64 {
65 icu::Locale locale = icu::Locale::getDefault();
66 std::vector<TextEngine::FontParser::FontDescriptor> descriptors =
67 parser_.GetVisibilityFonts(std::string(locale.getName()));
68 for (const auto& descriptor : descriptors) {
69 FontDescSharedPtr descriptorPtr = std::make_shared<TextEngine::FontParser::FontDescriptor>(descriptor);
70 stylishFullNameMap_[descriptorPtr->fullName].emplace(descriptorPtr);
71 }
72 }
73
ParserInstallFonts()74 void FontDescriptorCache::ParserInstallFonts()
75 {
76 installPathMap_.clear();
77 std::vector<std::string> fontPathList;
78 std::string fontPath = INSTALL_FONT_CONFIG_FILE;
79
80 if (!ParseInstalledConfigFile(fontPath, fontPathList)) {
81 TEXT_LOGE("Failed to parse the installed fonts");
82 return;
83 }
84
85 for (const auto& path : fontPathList) {
86 if (!ProcessInstalledFontPath(path)) {
87 TEXT_LOGE("Failed to process font path, path: %{public}s", path.c_str());
88 }
89 }
90 }
91
ParseInstalledConfigFile(const std::string& fontPath, std::vector<std::string>& fontPathList)92 bool FontDescriptorCache::ParseInstalledConfigFile(const std::string& fontPath, std::vector<std::string>& fontPathList)
93 {
94 std::shared_ptr<Drawing::FontMgr> fontMgr = Drawing::FontMgr::CreateDynamicFontMgr();
95 std::ifstream configFile(fontPath);
96 if (!configFile.is_open()) {
97 return false;
98 }
99 configFile.close();
100 return (fontMgr->ParseInstallFontConfig(fontPath, fontPathList) == Drawing::FontCheckCode::SUCCESSED);
101 }
102
ProcessInstalledFontPath(const std::string& path)103 bool FontDescriptorCache::ProcessInstalledFontPath(const std::string& path)
104 {
105 std::shared_ptr<Drawing::FontMgr> fontMgr = Drawing::FontMgr::CreateDefaultFontMgr();
106 int fd = open(path.c_str(), O_RDONLY);
107 if (fd == -1) {
108 return false;
109 }
110 std::vector<Drawing::FontByteArray> fullNameVec;
111 int ret = fontMgr->GetFontFullName(fd, fullNameVec);
112 close(fd);
113 if (ret != Drawing::FontCheckCode::SUCCESSED || fullNameVec.empty()) {
114 return false;
115 }
116 std::vector<std::string> fullNameStringVec;
117 for (const auto& fullName : fullNameVec) {
118 std::string fullNameString;
119 if (Drawing::ConvertToString(fullName.strData.get(), fullName.strLen, fullNameString)) {
120 fullNameStringVec.push_back(fullNameString);
121 } else {
122 fullNameStringVec.clear();
123 return false;
124 }
125 }
126 installPathMap_[path] = fullNameStringVec;
127 return true;
128 }
129
FontDescriptorScatter(FontDescSharedPtr desc)130 void FontDescriptorCache::FontDescriptorScatter(FontDescSharedPtr desc)
131 {
132 auto ret = allFontDescriptor_.emplace(desc);
133 if (!ret.second) {
134 return;
135 }
136
137 auto handleMapScatter = [&](auto& map, const auto& key) {
138 map[key].emplace(desc);
139 };
140
141 handleMapScatter(fontFamilyMap_, desc->fontFamily);
142 handleMapScatter(fullNameMap_, desc->fullName);
143 handleMapScatter(postScriptNameMap_, desc->postScriptName);
144 handleMapScatter(fontSubfamilyNameMap_, desc->fontSubfamily);
145
146 if (desc->weight > WEIGHT_400) {
147 boldCache_.emplace(desc);
148 }
149
150 if (desc->italic != 0) {
151 italicCache_.emplace(desc);
152 }
153
154 if (desc->monoSpace) {
155 monoSpaceCache_.emplace(desc);
156 }
157
158 if (desc->symbolic) {
159 symbolicCache_.emplace(desc);
160 }
161 }
162
GetInstallFontList()163 std::unordered_set<std::string> FontDescriptorCache::GetInstallFontList()
164 {
165 ParserInstallFonts();
166 std::unordered_set<std::string> fullNameList;
167 for (const auto& pathAndFonts : installPathMap_) {
168 for (const auto& fullName : pathAndFonts.second) {
169 fullNameList.emplace(fullName);
170 }
171 }
172 return fullNameList;
173 }
174
GetStylishFontList()175 std::unordered_set<std::string> FontDescriptorCache::GetStylishFontList()
176 {
177 std::unordered_set<std::string> fullNameList;
178 for (const auto& temp : stylishFullNameMap_) {
179 fullNameList.emplace(temp.first);
180 }
181 return fullNameList;
182 }
183
GetGenericFontList()184 std::unordered_set<std::string> FontDescriptorCache::GetGenericFontList()
185 {
186 std::unordered_set<std::string> fullNameList;
187 for (const auto& temp : allFontDescriptor_) {
188 fullNameList.emplace(temp->fullName);
189 }
190 return fullNameList;
191 }
192
ProcessSystemFontType(const int32_t& systemFontType, int32_t& fontType)193 bool FontDescriptorCache::ProcessSystemFontType(const int32_t& systemFontType, int32_t& fontType)
194 {
195 if ((systemFontType & (TextEngine::FontParser::SystemFontType::ALL |
196 TextEngine::FontParser::SystemFontType::GENERIC |
197 TextEngine::FontParser::SystemFontType::STYLISH |
198 TextEngine::FontParser::SystemFontType::INSTALLED)) != systemFontType) {
199 TEXT_LOGE("SystemFontType is invalid, systemFontType: %{public}d", systemFontType);
200 return false;
201 }
202 fontType = systemFontType;
203 if (systemFontType & TextEngine::FontParser::SystemFontType::ALL) {
204 fontType = TextEngine::FontParser::SystemFontType::GENERIC |
205 TextEngine::FontParser::SystemFontType::STYLISH |
206 TextEngine::FontParser::SystemFontType::INSTALLED;
207 }
208 return true;
209 }
210
GetSystemFontFullNamesByType(const int32_t& systemFontType, std::unordered_set<std::string>& fontList)211 void FontDescriptorCache::GetSystemFontFullNamesByType(const int32_t& systemFontType,
212 std::unordered_set<std::string>& fontList)
213 {
214 int32_t fontType;
215 if (!ProcessSystemFontType(systemFontType, fontType)) {
216 fontList.clear();
217 return;
218 }
219
220 if (fontType & TextEngine::FontParser::SystemFontType::GENERIC) {
221 auto fullNameList = GetGenericFontList();
222 fontList.insert(fullNameList.begin(), fullNameList.end());
223 }
224
225 if (fontType & TextEngine::FontParser::SystemFontType::STYLISH) {
226 auto fullNameList = GetStylishFontList();
227 fontList.insert(fullNameList.begin(), fullNameList.end());
228 }
229
230 if (fontType & TextEngine::FontParser::SystemFontType::INSTALLED) {
231 auto fullNameList = GetInstallFontList();
232 fontList.insert(fullNameList.begin(), fullNameList.end());
233 }
234 }
235
ParseInstallFontDescSharedPtrByName(const std::string& fullName, FontDescSharedPtr& result)236 bool FontDescriptorCache::ParseInstallFontDescSharedPtrByName(const std::string& fullName, FontDescSharedPtr& result)
237 {
238 ParserInstallFonts();
239 std::string path;
240 for (const auto& pathAndFonts : installPathMap_) {
241 for (const auto& font : pathAndFonts.second) {
242 if (font == fullName) {
243 path = pathAndFonts.first;
244 break;
245 }
246 }
247 if (!path.empty()) {
248 break;
249 }
250 }
251 // Setting the locale to English is to ensure consistency with the fullName format obtained from Skia.
252 std::string locale = ENGLISH;
253 std::vector<FontDescSharedPtr> descriptors;
254 if (parser_.ParserFontDescriptorFromPath(path, descriptors, locale)) {
255 for (auto& item : descriptors) {
256 if (item->fullName == fullName) {
257 result = item;
258 return true;
259 }
260 }
261 }
262 TEXT_LOGE_LIMIT3_MIN("Failed to parser fontDescriptor from path, path: %{public}s", path.c_str());
263 return false;
264 }
265
GetFontDescSharedPtrByFullName(const std::string& fullName, const int32_t& systemFontType, FontDescSharedPtr& result)266 void FontDescriptorCache::GetFontDescSharedPtrByFullName(const std::string& fullName,
267 const int32_t& systemFontType, FontDescSharedPtr& result)
268 {
269 if (fullName.empty()) {
270 TEXT_LOGE("Empty fullName is provided");
271 result = nullptr;
272 return;
273 }
274 int32_t fontType;
275 if (!ProcessSystemFontType(systemFontType, fontType)) {
276 result = nullptr;
277 return;
278 }
279 auto tryFindFontDescriptor = [&fullName, &result](const std::unordered_map<std::string,
280 std::set<FontDescSharedPtr>>& map) -> bool {
281 auto it = map.find(fullName);
282 if (it != map.end()) {
283 result = *(it->second.begin());
284 return true;
285 }
286 return false;
287 };
288 if ((fontType & TextEngine::FontParser::SystemFontType::GENERIC) && tryFindFontDescriptor(fullNameMap_)) {
289 return;
290 }
291 if ((fontType & TextEngine::FontParser::SystemFontType::STYLISH) && tryFindFontDescriptor(stylishFullNameMap_)) {
292 return;
293 }
294 if ((fontType & TextEngine::FontParser::SystemFontType::INSTALLED) &&
295 ParseInstallFontDescSharedPtrByName(fullName, result)) {
296 return;
297 }
298 TEXT_LOGD("Failed to get fontDescriptor by fullName: %{public}s", fullName.c_str());
299 result = nullptr;
300 }
301
HandleMapIntersection(std::set<FontDescSharedPtr>& finishRet, const std::string& name, std::unordered_map<std::string, std::set<FontDescSharedPtr>>& map)302 bool FontDescriptorCache::HandleMapIntersection(std::set<FontDescSharedPtr>& finishRet, const std::string& name,
303 std::unordered_map<std::string, std::set<FontDescSharedPtr>>& map)
304 {
305 if (name.empty()) {
306 return true;
307 }
308 auto iter = map.find(name);
309 if (iter == map.end()) {
310 return false;
311 }
312 if (finishRet.empty()) {
313 finishRet = iter->second;
314 } else {
315 std::set<FontDescSharedPtr> temp;
316 std::set_intersection(iter->second.begin(), iter->second.end(), finishRet.begin(), finishRet.end(),
317 std::insert_iterator<std::set<FontDescSharedPtr>>(temp, temp.begin()));
318 if (temp.empty()) {
319 return false;
320 }
321 finishRet = std::move(temp);
322 }
323 return true;
324 }
325
FilterBoldCache(int weight, std::set<FontDescSharedPtr>& finishRet)326 bool FontDescriptorCache::FilterBoldCache(int weight, std::set<FontDescSharedPtr>& finishRet)
327 {
328 if (weight < 0) {
329 return false;
330 }
331
332 if (weight == 0) {
333 return true;
334 }
335
336 std::set<FontDescSharedPtr> temp;
337 std::set<FontDescSharedPtr>::iterator begin;
338 std::set<FontDescSharedPtr>::iterator end;
339 if (!finishRet.empty()) {
340 begin = finishRet.begin();
341 end = finishRet.end();
342 } else if (weight > WEIGHT_400) {
343 begin = boldCache_.begin();
344 end = boldCache_.end();
345 } else {
346 begin = allFontDescriptor_.begin();
347 end = allFontDescriptor_.end();
348 }
349 std::for_each(begin, end, [&](FontDescSharedPtr item) {
350 if (item->weight == weight) {
351 temp.emplace(item);
352 }
353 });
354
355 if (temp.empty()) {
356 TEXT_LOGD("Failed to match weight");
357 return false;
358 }
359 finishRet = std::move(temp);
360 return true;
361 }
362
FilterWidthCache(int width, std::set<FontDescSharedPtr>& finishRet)363 bool FontDescriptorCache::FilterWidthCache(int width, std::set<FontDescSharedPtr>& finishRet)
364 {
365 if (width < 0) {
366 return false;
367 }
368
369 if (width == 0) {
370 return true;
371 }
372
373 std::set<FontDescSharedPtr> temp;
374 std::set<FontDescSharedPtr>::iterator begin;
375 std::set<FontDescSharedPtr>::iterator end;
376 if (!finishRet.empty()) {
377 begin = finishRet.begin();
378 end = finishRet.end();
379 } else {
380 begin = allFontDescriptor_.begin();
381 end = allFontDescriptor_.end();
382 }
383 std::for_each(begin, end, [&](FontDescSharedPtr item) {
384 if (item->width == width) {
385 temp.emplace(item);
386 }
387 });
388
389 if (temp.empty()) {
390 TEXT_LOGD("Failed to match width");
391 return false;
392 }
393 finishRet = std::move(temp);
394 return true;
395 }
396
FilterItalicCache(int italic, std::set<FontDescSharedPtr>& finishRet)397 bool FontDescriptorCache::FilterItalicCache(int italic, std::set<FontDescSharedPtr>& finishRet)
398 {
399 if (italic == 0) {
400 return true;
401 }
402 std::set<FontDescSharedPtr> temp;
403 if (!finishRet.empty()) {
404 std::for_each(finishRet.begin(), finishRet.end(), [&](FontDescSharedPtr item) {
405 if (item->italic != 0) {
406 temp.emplace(item);
407 }
408 });
409 } else {
410 temp = italicCache_;
411 }
412 if (temp.empty()) {
413 TEXT_LOGD("Failed to match italic");
414 return false;
415 }
416 finishRet = std::move(temp);
417 return true;
418 }
419
FilterMonoSpaceCache(bool monoSpace, std::set<FontDescSharedPtr>& finishRet)420 bool FontDescriptorCache::FilterMonoSpaceCache(bool monoSpace, std::set<FontDescSharedPtr>& finishRet)
421 {
422 if (!monoSpace) {
423 return true;
424 }
425
426 std::set<FontDescSharedPtr> temp;
427 if (!finishRet.empty()) {
428 std::for_each(finishRet.begin(), finishRet.end(), [&](FontDescSharedPtr item) {
429 if (item->monoSpace) {
430 temp.emplace(item);
431 }
432 });
433 } else {
434 temp = monoSpaceCache_;
435 }
436 if (temp.empty()) {
437 TEXT_LOGD("Failed to match monoSpace");
438 return false;
439 }
440 finishRet = std::move(temp);
441 return true;
442 }
443
FilterSymbolicCache(bool symbolic, std::set<FontDescSharedPtr>& finishRet)444 bool FontDescriptorCache::FilterSymbolicCache(bool symbolic, std::set<FontDescSharedPtr>& finishRet)
445 {
446 if (!symbolic) {
447 return true;
448 }
449 std::set<FontDescSharedPtr> temp;
450 if (!finishRet.empty()) {
451 std::for_each(finishRet.begin(), finishRet.end(), [&](FontDescSharedPtr item) {
452 if (item->symbolic) {
453 temp.emplace(item);
454 }
455 });
456 } else {
457 temp = symbolicCache_;
458 }
459 if (temp.empty()) {
460 TEXT_LOGD("Failed to match symbolic");
461 return false;
462 }
463 finishRet = std::move(temp);
464 return true;
465 }
466
IsDefault(FontDescSharedPtr desc)467 bool FontDescriptorCache::IsDefault(FontDescSharedPtr desc)
468 {
469 if (desc->fontFamily.empty() && desc->fullName.empty() && desc->postScriptName.empty()
470 && desc->fontSubfamily.empty() && desc->weight == 0 && desc->width == 0 && desc->italic == 0
471 && !desc->monoSpace && !desc->symbolic) {
472 return true;
473 }
474 return false;
475 }
476
MatchFromFontDescriptor(FontDescSharedPtr desc, std::set<FontDescSharedPtr>& result)477 void FontDescriptorCache::MatchFromFontDescriptor(FontDescSharedPtr desc, std::set<FontDescSharedPtr>& result)
478 {
479 if (desc == nullptr) {
480 TEXT_LOGE("desc is nullptr");
481 return;
482 }
483
484 if (IsDefault(desc)) {
485 result = std::set<FontDescSharedPtr>(allFontDescriptor_.begin(), allFontDescriptor_.end());
486 return;
487 }
488
489 std::set<FontDescSharedPtr> finishRet;
490 TEXT_INFO_CHECK(HandleMapIntersection(finishRet, desc->fontFamily, fontFamilyMap_), return,
491 "Failed to match fontFamily");
492 TEXT_INFO_CHECK(HandleMapIntersection(finishRet, desc->fullName, fullNameMap_), return, "Failed to match fullName");
493 TEXT_INFO_CHECK(HandleMapIntersection(finishRet, desc->postScriptName, postScriptNameMap_), return,
494 "Failed to match postScriptName");
495 TEXT_INFO_CHECK(HandleMapIntersection(finishRet, desc->fontSubfamily, fontSubfamilyNameMap_), return,
496 "Failed to match fontSubfamily");
497
498 TEXT_CHECK(FilterBoldCache(desc->weight, finishRet), return);
499 TEXT_CHECK(FilterWidthCache(desc->width, finishRet), return);
500 TEXT_CHECK(FilterItalicCache(desc->italic, finishRet), return);
501 TEXT_CHECK(FilterMonoSpaceCache(desc->monoSpace, finishRet), return);
502 TEXT_CHECK(FilterSymbolicCache(desc->symbolic, finishRet), return);
503 result = std::move(finishRet);
504 }
505
Dump()506 void FontDescriptorCache::Dump()
507 {
508 TEXT_LOGD("allFontDescriptor size: %{public}zu, fontFamilyMap size: %{public}zu, fullNameMap size: %{public}zu \
509 postScriptNameMap size: %{public}zu, fontSubfamilyNameMap size: %{public}zu, boldCache size: %{public}zu \
510 italicCache size: %{public}zu, monoSpaceCache size: %{public}zu, symbolicCache size: %{public}zu",
511 allFontDescriptor_.size(), fontFamilyMap_.size(), fullNameMap_.size(), postScriptNameMap_.size(),
512 fontSubfamilyNameMap_.size(), boldCache_.size(), italicCache_.size(), monoSpaceCache_.size(),
513 symbolicCache_.size());
514 }
515 }