1 // Copyright (c) 2023 Huawei Device Co., Ltd. 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 "FontConfig_ohos.h"
6
7 #include <algorithm>
8 #include <array>
9 #include <cstring>
10 #include <dirent.h>
11 #include <fstream>
12 #include <functional>
13 #include <libgen.h>
14 #include <sys/stat.h>
15 #include <sys/types.h>
16 #include <unistd.h>
17
18 #if defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_WIN) or defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_MAC) or \
19 defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_LINUX)
20 #define SK_BUILD_FONT_MGR_FOR_PREVIEW
21 #endif
22
23 #ifdef SK_BUILD_FONT_MGR_FOR_OHOS
24 #include <parameters.h>
25 #endif
26
27 #include "SkFontStyle.h"
28 #include "SkString.h"
29 #include "securec.h"
30
31 using namespace ErrorCode;
32 static const char* PRODUCT_DEFAULT_CONFIG = "/system/etc/productfontconfig.json";
33
34 #ifdef SK_BUILD_FONT_MGR_FOR_OHOS
35 static const bool G_IS_HMSYMBOL_ENABLE =
36 (std::atoi(OHOS::system::GetParameter("persist.sys.graphic.hmsymbolcfg.enable", "1").c_str()) != 0);
37 #else
38 static const bool G_IS_HMSYMBOL_ENABLE = true;
39 #endif
40
41 #ifdef SK_BUILD_FONT_MGR_FOR_PREVIEW
42 static const char* OHOS_DEFAULT_CONFIG = "fontconfig_ohos.json";
43 /*! Constructor
44 * \param fontScanner the scanner to get the font information from a font file
45 * \param fname the full name of system font configuration document.
46 * \n The default value is '/system/etc/fontconfig_ohos.json', if fname is given null
47 */
FontConfig_OHOS(const SkTypeface_FreeType::Scanner & fontScanner,const char * fname)48 FontConfig_OHOS::FontConfig_OHOS(const SkTypeface_FreeType::Scanner& fontScanner, const char* fname)
49 : fFontScanner(fontScanner)
50 {
51 int err = parseConfig(fname);
52 if (err != NO_ERROR) {
53 return;
54 }
55 loadHMSymbol();
56 }
57 #else
58 static const char* OHOS_DEFAULT_CONFIG = "/system/etc/fontconfig_ohos.json";
59 /*! Constructor
60 * \param fontScanner the scanner to get the font information from a font file
61 * \param fname the full name of system font configuration document.
62 * \n The default value is '/system/etc/fontconfig_ohos.json', if fname is given null
63 */
FontConfig_OHOS(const SkTypeface_FreeType::Scanner & fontScanner,const char * fname)64 FontConfig_OHOS::FontConfig_OHOS(const SkTypeface_FreeType::Scanner& fontScanner, const char* fname)
65 : fFontScanner(fontScanner)
66 {
67 int err = checkProductFile(fname);
68 if (err != NO_ERROR) {
69 return;
70 }
71 loadHMSymbol();
72 }
73 #endif
74
75 /*! To get the count of font style sets supported in the system
76 * \return The count of font style sets in generic family
77 */
getFamilyCount() const78 int FontConfig_OHOS::getFamilyCount() const
79 {
80 return fFontCollection.fGeneric.size();
81 }
82
83 /*! To match the fallback typeface by the given style and character
84 * this function will traverse all the fallback typefaces
85 * \param character the character to be matched
86 * \param style the style to be matched
87 * \return the matched typeface
88 */
matchFallback(SkUnichar character,const SkFontStyle & style) const89 SkTypeface* FontConfig_OHOS::matchFallback(SkUnichar character, const SkFontStyle& style) const
90 {
91 int16_t index = charRangeIndex(character);
92 if (index < 0) {
93 return nullptr;
94 }
95 for (const auto& i : fFontCollection.fRangeToIndex[index]) {
96 const auto& typefaces = fFontCollection.fFallback[i].typefaces;
97 if (!typefaces.empty() && typefaces[0]->unicharToGlyph(character)) {
98 return SkSafeRef(matchFontStyle(typefaces, style).get());
99 }
100 }
101 return nullptr;
102 }
103
104 /*! To match the fallback typeface by the given index style and character
105 * this function only traverse the fallback typefaces in the given index
106 * \param index the index of fallback typefaces
107 * \param character the character to be matched
108 * \param style the style to be matched
109 * \return the matched typeface
110 */
matchFallback(size_t index,SkUnichar character,const SkFontStyle & style) const111 SkTypeface* FontConfig_OHOS::matchFallback(size_t index, SkUnichar character, const SkFontStyle& style) const
112 {
113 if (index >= fFontCollection.fFallback.size()) {
114 return nullptr;
115 }
116 const auto& typefaces = fFontCollection.fFallback[index].typefaces;
117 if (!typefaces.empty() && typefaces[0]->unicharToGlyph(character)) {
118 auto typeface = matchFontStyle(typefaces, style);
119 return SkSafeRef(typeface.get());
120 }
121 return nullptr;
122 }
123
124 /*! To match the fallback typeface by the given function
125 * this function will traverse all the fallback typefaces
126 * \param match the judge func, if the func return -1, it means the language tag is not matched
127 * \return the matched fallback typefaces' index set
128 */
matchFallbackByBCP47(std::function<int (const std::string &)> match) const129 std::vector<size_t> FontConfig_OHOS::matchFallbackByBCP47(std::function<int(const std::string&)> match) const
130 {
131 std::vector<size_t> res;
132 for (size_t i = 0; i < fFontCollection.fFallback.size(); i += 1) {
133 if (match(fFontCollection.fFallback[i].lang) != -1) {
134 res.push_back(i);
135 }
136 }
137 return res;
138 }
139
140 /*! To get a typeface by the given family name and style
141 * this function will traverse both the fallback and general typefaces
142 * \param familyName the family name of the fallback typeface
143 * \param style the style of the fallback typeface
144 * \return the matched typeface
145 */
getFallbackTypeface(const SkString & familyName,const SkFontStyle & style) const146 sk_sp<SkTypeface_OHOS> FontConfig_OHOS::getFallbackTypeface(const SkString& familyName, const SkFontStyle& style) const
147 {
148 std::pair<size_t, FontType> res;
149 if (!fFontCollection.getIndexByFamilyName(familyName.c_str(), res)) {
150 return nullptr;
151 }
152
153 const auto& tpSet = fFontCollection.getSet(true)[res.first].typefaces;
154 if (tpSet.size() == 0) {
155 return nullptr;
156 }
157 return FontConfig_OHOS::matchFontStyle(tpSet, style);
158 }
159
160 /*! To get the family name of the default font style set
161 * \param[out] familyName a pointer of SkString object, to which the family value will be set.
162 * \return The count of typeface in this font style set
163 * \n Return -1, if there is no any font style set in the system.
164 */
getDefaultFamily(SkString & familyName) const165 int FontConfig_OHOS::getDefaultFamily(SkString& familyName) const
166 {
167 return getFamilyName(0, familyName);
168 }
169
170 /*! To get the family name of a font style set
171 * \param index the index of a font style set in generic family
172 * \param[out] familyName a pointer of SkString object, to which the family value will be set
173 * \return The count of typeface in the font style set
174 * \n Return -1, if the 'index' is out of range
175 */
getFamilyName(size_t index,SkString & familyName) const176 int FontConfig_OHOS::getFamilyName(size_t index, SkString& familyName) const
177 {
178 if (index >= getFamilyCount()) {
179 familyName = "";
180 return -1;
181 }
182 familyName = fFontCollection.fGeneric[index].alias.c_str();
183 return fFontCollection.fGeneric[index].typefaces.size();
184 }
185
186 /*! To get the count of a font style set
187 * \param styleIndex the index of a font style set
188 * \param isFallback to indicate the font style set is from generic family or fallback family
189 * \n false , the font style set is from generic family list
190 * \n true, the font style set is from fallback family list
191 * \return The count of typeface in the font style set
192 */
getTypefaceCount(size_t styleIndex,bool isFallback) const193 size_t FontConfig_OHOS::getTypefaceCount(size_t styleIndex, bool isFallback) const
194 {
195 auto& set = fFontCollection.getSet(isFallback);
196 return (styleIndex < set.size()) ? set[styleIndex].typefaces.size() : 0;
197 }
198
199 /*! To get a typeface
200 * \param styleIndex the index of a font style set
201 * \param index the index of a typeface in its style set
202 * \param isFallback false, the font style set is generic
203 * \n true, the font style set is fallback
204 * \return The pointer of a typeface
205 * \n Return null, if 'styleIndex' or 'index' is out of range
206 */
getTypeface(size_t styleIndex,size_t index,bool isFallback) const207 SkTypeface_OHOS* FontConfig_OHOS::getTypeface(size_t styleIndex, size_t index, bool isFallback) const
208 {
209 sk_sp<SkTypeface_OHOS> typeface = getTypefaceSP(styleIndex, index, isFallback);
210 return (typeface == nullptr) ? nullptr : typeface.get();
211 }
212
getTypefaceSP(size_t styleIndex,size_t index,bool isFallback) const213 sk_sp<SkTypeface_OHOS> FontConfig_OHOS::getTypefaceSP(size_t styleIndex, size_t index, bool isFallback) const
214 {
215 auto& fontSet = fFontCollection.getSet(isFallback);
216 if (styleIndex <= fontSet.size()) {
217 // if index less than typefaces' size, return the ptr
218 return (index < fontSet[styleIndex].typefaces.size()) ? fontSet[styleIndex].typefaces[index] : nullptr;
219 }
220 return nullptr;
221 }
222
223 /*! To get a typeface
224 * \param styleIndex the index a font style set
225 * \param style the font style to be matching
226 * \param isFallback false, the font style set is generic
227 * \n true, the font style set is fallback
228 * \return An object of typeface whose font style is the closest matching to 'style'
229 * \n Return null, if 'styleIndex' is out of range
230 */
getTypeface(size_t styleIndex,const SkFontStyle & style,bool isFallback) const231 SkTypeface_OHOS* FontConfig_OHOS::getTypeface(size_t styleIndex, const SkFontStyle& style, bool isFallback) const
232 {
233 auto& fontSet = fFontCollection.getSet(isFallback);
234 if (styleIndex >= fontSet.size()) {
235 return nullptr;
236 }
237
238 const std::vector<sk_sp<SkTypeface_OHOS>>& pSet = fontSet[styleIndex].typefaces;
239 sk_sp<SkTypeface_OHOS> tp = matchFontStyle(pSet, style);
240 return tp.get();
241 }
242
243 /*! To get the index of a font style set
244 * \param familyName the family name of the font style set
245 * \n get the index of default font style set, if 'familyName' is null
246 * \param[out] isFallback to tell if the family is from generic or fallback to the caller.
247 * \n isFallback is false, if the font style is from generic family list
248 * \n isFallback is true, if the font style is from fallback family list
249 * \param[out] index the index of the font set
250 * \return The index of the font style set
251 * \n Return false, if 'familyName' is not found in the system
252 */
getStyleIndex(const char * familyName,bool & isFallback,size_t & index) const253 bool FontConfig_OHOS::getStyleIndex(const char* familyName, bool& isFallback, size_t& index) const
254 {
255 if (familyName == nullptr) {
256 isFallback = false;
257 return true;
258 }
259
260 std::lock_guard<std::mutex> lock(fFontMutex);
261 std::pair<size_t, FontType> res;
262 if (fFontCollection.getIndexByFamilyName(familyName, res)) {
263 isFallback = res.second == FontType::Fallback;
264 index = res.first;
265 return true;
266 }
267 return false;
268 }
269
270 /*! Find the closest matching typeface
271 * \param typefaceSet a typeface set belonging to the same font style set
272 * \param pattern the font style to be matching
273 * \return The typeface object which is the closest matching to 'pattern'
274 * \n Return null, if the count of typeface is 0
275 */
matchFontStyle(const std::vector<sk_sp<SkTypeface_OHOS>> & typefaceSet,const SkFontStyle & pattern)276 sk_sp<SkTypeface_OHOS> FontConfig_OHOS::matchFontStyle(
277 const std::vector<sk_sp<SkTypeface_OHOS>>& typefaceSet, const SkFontStyle& pattern)
278 {
279 int count = typefaceSet.size();
280 if (count == 1) {
281 return typefaceSet[0];
282 }
283 sk_sp<SkTypeface_OHOS> res = nullptr;
284 uint32_t minDiff = 0xFFFFFFFF;
285 for (int i = 0; i < count; i++) {
286 const SkFontStyle& fontStyle = typefaceSet[i]->fontStyle();
287 uint32_t diff = getFontStyleDifference(pattern, fontStyle);
288 if (diff < minDiff) {
289 minDiff = diff;
290 res = typefaceSet[i];
291 }
292 }
293 return res;
294 }
295
296 /*! To get the difference between a font style and the matching font style
297 * \param dstStyle the style to be matching
298 * \param srcStyle a font style
299 * \return The difference value of a specified style with the matching style
300 */
getFontStyleDifference(const SkFontStyle & dstStyle,const SkFontStyle & srcStyle)301 uint32_t FontConfig_OHOS::getFontStyleDifference(const SkFontStyle& dstStyle,
302 const SkFontStyle& srcStyle)
303 {
304 int normalWidth = SkFontStyle::kNormal_Width;
305 int dstWidth = dstStyle.width();
306 int srcWidth = srcStyle.width();
307
308 uint32_t widthDiff = 0;
309 // The maximum font width is kUltraExpanded_Width i.e. '9'.
310 // If dstWidth <= kNormal_Width (5), first check narrower values, then wider values.
311 // If dstWidth > kNormal_Width, first check wider values, then narrower values.
312 // When dstWidth and srcWidth are at different side of kNormal_Width,
313 // the width difference between them should be more than 5 (9/2+1)
314 constexpr int kWidthDiffThreshold = 9 / 2 + 1;
315 if (dstWidth <= normalWidth) {
316 widthDiff = (srcWidth <= dstWidth) ? (dstWidth - srcWidth)
317 : (srcWidth - dstWidth + kWidthDiffThreshold);
318 } else {
319 widthDiff = (srcWidth >= dstWidth) ? (srcWidth - dstWidth)
320 : (dstWidth - srcWidth + kWidthDiffThreshold);
321 }
322
323 constexpr int SLANT_RANGE = 3;
324 int diffSlantValue[SLANT_RANGE][SLANT_RANGE] = {
325 {0, 2, 1},
326 {2, 0, 1},
327 {2, 1, 0}
328 };
329 if (dstStyle.slant() < 0 || dstStyle.slant() >= SLANT_RANGE ||
330 srcStyle.slant() < 0 || srcStyle.slant() >= SLANT_RANGE) {
331 return 0;
332 }
333 uint32_t slantDiff = diffSlantValue[dstStyle.slant()][srcStyle.slant()];
334
335 int dstWeight = dstStyle.weight();
336 int srcWeight = srcStyle.weight();
337 uint32_t weightDiff = 0;
338
339 // The maximum weight is kExtraBlack_Weight (1000), when dstWeight and srcWeight are at the different
340 // side of kNormal_Weight, the weight difference between them should be more than 500 (1000/2)
341 constexpr int kWeightDiffThreshold = 1000 / 2;
342 if ((dstWeight == SkFontStyle::kNormal_Weight && srcWeight == SkFontStyle::kMedium_Weight) ||
343 (dstWeight == SkFontStyle::kMedium_Weight && srcWeight == SkFontStyle::kNormal_Weight)) {
344 weightDiff = 50;
345 } else if (dstWeight <= SkFontStyle::kNormal_Weight) {
346 weightDiff = (srcWeight <= dstWeight) ? (dstWeight - srcWeight)
347 : (srcWeight - dstWeight + kWeightDiffThreshold);
348 } else if (dstWeight > SkFontStyle::kNormal_Weight) {
349 weightDiff = (srcWeight >= dstWeight) ? (srcWeight - dstWeight)
350 : (dstWeight - srcWeight + kWeightDiffThreshold);
351 }
352 // The first 2 bytes to save weight difference, the third byte to save slant difference,
353 // and the fourth byte to save width difference
354 uint32_t diff = (widthDiff << 24) + (slantDiff << 16) + weightDiff;
355 return diff;
356 }
357
parseConfig(const char * fname)358 int FontConfig_OHOS::parseConfig(const char* fname)
359 {
360 if (fname == nullptr) {
361 fname = OHOS_DEFAULT_CONFIG;
362 }
363 Json::Value root;
364 int err = checkConfigFile(fname, root);
365 if (err != NO_ERROR) {
366 return err;
367 }
368
369 if (root["font_dir"].isArray()) {
370 parseFontDir(fname, root["font_dir"]);
371 }
372 if (root["fonts"].isArray()) {
373 parseFonts(root["fonts"]);
374 }
375
376 return NO_ERROR;
377 }
378
379 template<>
is() const380 bool Json::Value::is<UnicodeRange>() const
381 {
382 if (!isArray() || size() != RANGE_SIZE) {
383 return false;
384 }
385 return std::all_of(begin(), end(), [](const Value& item) { return item.isUInt(); });
386 }
387
388 template<>
as() const389 UnicodeRange Json::Value::as<UnicodeRange>() const
390 {
391 UnicodeRange res;
392 size_t index = 0;
393 for (const auto& item : *this) {
394 res[index++] = item.asUInt();
395 }
396 return res;
397 }
398
399 template<class T>
GetValue(T & v,const Json::Value & root)400 void GetValue(T& v, const Json::Value& root)
401 {
402 if (root.is<T>()) {
403 v = std::move(root.as<T>());
404 }
405 }
406
407 #define GEN_GET_FONT_FUNC(f, member) ([](FontJson&(f), const Json::Value& value) { GetValue((f).member, value); })
408
409 /*! parse the font item from the json document
410 * \param array the font array from the json document
411 * \return NO_ERROR successful
412 */
parseFonts(const Json::Value & array)413 int FontConfig_OHOS::parseFonts(const Json::Value& array)
414 {
415 const std::unordered_map<std::string, std::function<void(FontConfig_OHOS::FontJson&, const Json::Value&)>>
416 funcMap = { { "type", GEN_GET_FONT_FUNC(f, type) }, { "family", GEN_GET_FONT_FUNC(f, family) },
417 { "index", GEN_GET_FONT_FUNC(f, index) }, { "weight", GEN_GET_FONT_FUNC(f, weight) },
418 { "lang", GEN_GET_FONT_FUNC(f, lang) }, { "file", GEN_GET_FONT_FUNC(f, file) },
419 { "alias", GEN_GET_FONT_FUNC(f, alias) }, { "range", GEN_GET_FONT_FUNC(f, range)} };
420
421 for (const auto& font : array) {
422 if (!font.isObject()) {
423 continue;
424 }
425
426 FontJson f;
427 for (const auto& key : font.getMemberNames()) {
428 if (funcMap.count(key)) {
429 funcMap.at(key)(f, font[key]);
430 }
431 }
432
433 sk_sp<SkTypeface_OHOS> typeface = nullptr;
434 for (auto& dir : fFontDir) {
435 std::string path = dir + f.file;
436 if (loadFont(path.c_str(), f, typeface) == 0) {
437 fFontCollection.emplaceFont(std::move(f), std::move(typeface));
438 break;
439 }
440 }
441 }
442 forAll([this](Font& f) { sortTypefaceSet(f.typefaces); });
443 return NO_ERROR;
444 }
445
446 /*! check the system font configuration document
447 * \param fname the full name of the font configuration document
448 * \return NO_ERROR successful
449 * \return ERROR_CONFIG_NOT_FOUND config document is not found
450 * \return ERROR_CONFIG_FORMAT_NOT_SUPPORTED config document format is not supported
451 */
checkConfigFile(const char * fname,Json::Value & root)452 int FontConfig_OHOS::checkConfigFile(const char* fname, Json::Value& root)
453 {
454 std::ifstream fstream(fname);
455
456 if (!fstream.is_open()) {
457 return ERROR_CONFIG_NOT_FOUND;
458 }
459
460 Json::Reader reader;
461 bool isJson = reader.parse(fstream, root, false);
462 if (!isJson) {
463 return ERROR_CONFIG_FORMAT_NOT_SUPPORTED;
464 }
465 return NO_ERROR;
466 }
467
468 /*! To parse 'fontdir' attribute
469 * \param root the root node of 'fontdir'
470 * \return NO_ERROR successful
471 */
parseFontDir(const char * fname,const Json::Value & root)472 int FontConfig_OHOS::parseFontDir(const char* fname, const Json::Value& root)
473 {
474 for (auto& path : root) {
475 if (!path.isString()) {
476 continue;
477 }
478 std::string dir;
479 #ifdef SK_BUILD_FONT_MGR_FOR_PREVIEW
480 if (strcmp(fname, OHOS_DEFAULT_CONFIG) == 0) {
481 dir = (path.asString() != "/system/fonts/") ? path.asString() : "fonts/";
482 } else {
483 dir = (path.asString() != "/system/fonts/")
484 ? path.asString() : "../../../../hms/previewer/resources/fonts/";
485 }
486 #else
487 dir = path.asString();
488 #endif
489 fFontDir.push_back(std::move(dir));
490 }
491 return NO_ERROR;
492 }
493
494 /*! To load font information from a font file
495 * \param fname the full name of a font file
496 * \param info the font information read from json document
497 * \param typeface the typeface to be loaded
498 * \return NO_ERROR successful
499 * \return ERROR_FONT_NOT_EXIST font file is not exist
500 * \return ERROR_FONT_INVALID_STREAM the stream is not recognized
501 */
loadFont(const char * fname,FontJson & info,sk_sp<SkTypeface_OHOS> & typeface)502 int FontConfig_OHOS::loadFont(const char* fname, FontJson& info, sk_sp<SkTypeface_OHOS>& typeface) {
503 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(fname);
504 if (stream == nullptr) {
505 return ERROR_FONT_NOT_EXIST;
506 }
507 FontInfo font(fname, info.index);
508 if (!fFontScanner.scanFont(stream.get(), info.index, &font.familyName, &font.style, &font.isFixedWidth, nullptr)) {
509 return ERROR_FONT_INVALID_STREAM;
510 }
511
512 const char* temp = (info.type == FontType::Generic) ? info.alias.c_str() : "";
513 SkString family(temp);
514 typeface = sk_make_sp<SkTypeface_OHOS>(family, font);
515 return NO_ERROR;
516 }
517
loadHMSymbol()518 void FontConfig_OHOS::loadHMSymbol()
519 {
520 if (!G_IS_HMSYMBOL_ENABLE) {
521 return;
522 }
523 for (auto& dir : fFontDir) {
524 if (skia::text::HmSymbolConfig_OHOS::LoadSymbolConfig(
525 "hm_symbol_config_next.json", SkString(dir.c_str())) == NO_ERROR) {
526 return;
527 }
528 }
529 }
530
531 /*! To sort the typeface set
532 * \param typefaceSet the typeface set to be sorted
533 */
sortTypefaceSet(std::vector<sk_sp<SkTypeface_OHOS>> & typefaceSet)534 void FontConfig_OHOS::sortTypefaceSet(std::vector<sk_sp<SkTypeface_OHOS>>& typefaceSet)
535 {
536 std::sort(typefaceSet.begin(), typefaceSet.end(), [](const auto& a, const auto& b) {
537 return (a->fontStyle().weight() < b->fontStyle().weight()) ||
538 (a->fontStyle().weight() == b->fontStyle().weight() && a->fontStyle().slant() < b->fontStyle().slant());
539 });
540 }
541
judgeFileExist()542 bool FontConfig_OHOS::judgeFileExist()
543 {
544 bool haveFile = false;
545 for (const auto& path : fFontDir) {
546 DIR* dir = opendir(path.c_str());
547 if (dir == nullptr) {
548 continue;
549 }
550 struct dirent* node = nullptr;
551 #if defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_WIN)
552 struct stat fileStat;
553 #endif
554 while ((node = readdir(dir))) {
555 #if defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_WIN)
556 stat(node->d_name, &fileStat);
557 if (S_ISDIR(fileStat.st_mode)) {
558 continue;
559 }
560 #else
561 if (node->d_type != DT_REG) {
562 continue;
563 }
564 #endif
565 const char* fileName = node->d_name;
566 int len = strlen(fileName);
567 int suffixLen = strlen(".ttf");
568 if (len < suffixLen ||
569 (strncmp(fileName + len - suffixLen, ".ttf", suffixLen) != 0 &&
570 strncmp(fileName + len - suffixLen, ".otf", suffixLen) != 0 &&
571 strncmp(fileName + len - suffixLen, ".ttc", suffixLen) != 0 &&
572 strncmp(fileName + len - suffixLen, ".otc", suffixLen) != 0)) {
573 continue;
574 }
575 haveFile = true;
576 break;
577 }
578 (void)closedir(dir);
579 if (haveFile) {
580 break;
581 }
582 }
583 return haveFile;
584 }
585
checkProductFile(const char * fname)586 int FontConfig_OHOS::checkProductFile(const char* fname)
587 {
588 std::lock_guard<std::mutex> lock(fFontMutex);
589 int err = parseConfig(PRODUCT_DEFAULT_CONFIG);
590 if (err != NO_ERROR || !judgeFileExist()) {
591 err = parseConfig(OHOS_DEFAULT_CONFIG);
592 }
593 return err;
594 }
595
Font(FontJson & info)596 FontConfig_OHOS::Font::Font(FontJson& info)
597 : slant(info.slant), weight(info.weight), alias(info.alias), family(info.family), lang(info.lang)
598 {
599 this->type = info.type >= FontType::NumOfFontType ? FontType::Generic : static_cast<FontType>(info.type);
600 }
601
containRange(const UnicodeRange & range,size_t index)602 bool FontConfig_OHOS::containRange(const UnicodeRange& range, size_t index)
603 {
604 // because the range is 11 32-bit, so we need to / 32 means >> 5
605 int16_t i = index >> 5;
606 // get the bit position by mod 32 which means & 31
607 int16_t bit = index & 31;
608 return ((range[i] >> bit) & 1) != 0;
609 }
610
emplaceFont(FontJson && fj,sk_sp<SkTypeface_OHOS> && typeface)611 void FontConfig_OHOS::FontCollection::emplaceFont(FontJson&& fj, sk_sp<SkTypeface_OHOS>&& typeface)
612 {
613 if (fj.family.empty()) {
614 return;
615 }
616 Font f(fj);
617 auto& targetVec = (f.type == FontType::Generic) ? fGeneric : fFallback;
618 auto& targetName = (f.type == FontType::Generic) ? f.alias : f.family;
619 // generic must have alias
620 auto exist = fIndexMap.find(targetName);
621 // if not found, insert directly
622 if (exist == fIndexMap.end()) {
623 for (size_t i = 0; i < UNICODE_RANGE_SIZE && f.type == FontType::Fallback; i += 1) {
624 if (containRange(fj.range, i)) {
625 fRangeToIndex[i].push_back(targetVec.size());
626 }
627 }
628 fIndexMap.emplace(targetName, std::make_pair(targetVec.size(), f.type));
629 targetVec.emplace_back(f);
630 targetVec.back().typefaces.emplace_back(typeface);
631 } else {
632 // if exist, add the typeface to the font
633 targetVec[exist->second.first].typefaces.emplace_back(typeface);
634 }
635 }
636
getIndexByFamilyName(const std::string & family,std::pair<size_t,FontType> & res) const637 bool FontConfig_OHOS::FontCollection::getIndexByFamilyName(
638 const std::string& family, std::pair<size_t, FontType>& res) const
639 {
640 if (fIndexMap.count(family)) {
641 res = fIndexMap.at(family);
642 return true;
643 }
644 return false;
645 }
646
getSet(bool isFallback) const647 const std::vector<FontConfig_OHOS::Font>& FontConfig_OHOS::FontCollection::getSet(bool isFallback) const
648 {
649 return isFallback ? fFallback : fGeneric;
650 }
651
forAll(std::function<void (FontConfig_OHOS::Font &)> func)652 void FontConfig_OHOS::FontCollection::forAll(std::function<void(FontConfig_OHOS::Font&)> func)
653 {
654 for (auto& f : fFallback) {
655 func(f);
656 }
657 for (auto& f : fGeneric) {
658 func(f);
659 }
660 }
661
charRangeIndex(SkUnichar unicode)662 int16_t FontConfig_OHOS::charRangeIndex(SkUnichar unicode)
663 {
664 auto it = fRangeMap.upper_bound({ unicode, UINT32_MAX });
665 if (it != fRangeMap.begin()) {
666 --it;
667 }
668 if (unicode >= it->first.first && unicode <= it->first.second) {
669 return it->second;
670 }
671 return -1;
672 }
673
674 const std::map<std::pair<uint32_t, uint32_t>, int16_t> FontConfig_OHOS::fRangeMap {
675 { { 0x0, 0x7F }, 0 },
676 { { 0x80, 0xFF }, 1 },
677 { { 0x100, 0x17F }, 2 },
678 { { 0x180, 0x24F }, 3 },
679 { { 0x250, 0x2AF }, 4 },
680 { { 0x2B0, 0x2FF }, 5 },
681 { { 0x300, 0x36F }, 6 },
682 { { 0x370, 0x3FF }, 7 },
683 { { 0x400, 0x4FF }, 8 },
684 { { 0x500, 0x52F }, 9 },
685 { { 0x530, 0x58F }, 10 },
686 { { 0x590, 0x5FF }, 11 },
687 { { 0x600, 0x6FF }, 12 },
688 { { 0x700, 0x74F }, 13 },
689 { { 0x750, 0x77F }, 14 },
690 { { 0x780, 0x7BF }, 15 },
691 { { 0x7C0, 0x7FF }, 16 },
692 { { 0x800, 0x83F }, 17 },
693 { { 0x840, 0x85F }, 18 },
694 { { 0x860, 0x86F }, 19 },
695 { { 0x870, 0x89F }, 20 },
696 { { 0x8A0, 0x8FF }, 21 },
697 { { 0x900, 0x97F }, 22 },
698 { { 0x980, 0x9FF }, 23 },
699 { { 0xA00, 0xA7F }, 24 },
700 { { 0xA80, 0xAFF }, 25 },
701 { { 0xB00, 0xB7F }, 26 },
702 { { 0xB80, 0xBFF }, 27 },
703 { { 0xC00, 0xC7F }, 28 },
704 { { 0xC80, 0xCFF }, 29 },
705 { { 0xD00, 0xD7F }, 30 },
706 { { 0xD80, 0xDFF }, 31 },
707 { { 0xE00, 0xE7F }, 32 },
708 { { 0xE80, 0xEFF }, 33 },
709 { { 0xF00, 0xFFF }, 34 },
710 { { 0x1000, 0x109F }, 35 },
711 { { 0x10A0, 0x10FF }, 36 },
712 { { 0x1100, 0x11FF }, 37 },
713 { { 0x1200, 0x137F }, 38 },
714 { { 0x1380, 0x139F }, 39 },
715 { { 0x13A0, 0x13FF }, 40 },
716 { { 0x1400, 0x167F }, 41 },
717 { { 0x1680, 0x169F }, 42 },
718 { { 0x16A0, 0x16FF }, 43 },
719 { { 0x1700, 0x171F }, 44 },
720 { { 0x1720, 0x173F }, 45 },
721 { { 0x1740, 0x175F }, 46 },
722 { { 0x1760, 0x177F }, 47 },
723 { { 0x1780, 0x17FF }, 48 },
724 { { 0x1800, 0x18AF }, 49 },
725 { { 0x18B0, 0x18FF }, 50 },
726 { { 0x1900, 0x194F }, 51 },
727 { { 0x1950, 0x197F }, 52 },
728 { { 0x1980, 0x19DF }, 53 },
729 { { 0x19E0, 0x19FF }, 54 },
730 { { 0x1A00, 0x1A1F }, 55 },
731 { { 0x1A20, 0x1AAF }, 56 },
732 { { 0x1AB0, 0x1AFF }, 57 },
733 { { 0x1B00, 0x1B7F }, 58 },
734 { { 0x1B80, 0x1BBF }, 59 },
735 { { 0x1BC0, 0x1BFF }, 60 },
736 { { 0x1C00, 0x1C4F }, 61 },
737 { { 0x1C50, 0x1C7F }, 62 },
738 { { 0x1C80, 0x1C8F }, 63 },
739 { { 0x1C90, 0x1CBF }, 64 },
740 { { 0x1CC0, 0x1CCF }, 65 },
741 { { 0x1CD0, 0x1CFF }, 66 },
742 { { 0x1D00, 0x1D7F }, 67 },
743 { { 0x1D80, 0x1DBF }, 68 },
744 { { 0x1DC0, 0x1DFF }, 69 },
745 { { 0x1E00, 0x1EFF }, 70 },
746 { { 0x1F00, 0x1FFF }, 71 },
747 { { 0x2000, 0x206F }, 72 },
748 { { 0x2070, 0x209F }, 73 },
749 { { 0x20A0, 0x20CF }, 74 },
750 { { 0x20D0, 0x20FF }, 75 },
751 { { 0x2100, 0x214F }, 76 },
752 { { 0x2150, 0x218F }, 77 },
753 { { 0x2190, 0x21FF }, 78 },
754 { { 0x2200, 0x22FF }, 79 },
755 { { 0x2300, 0x23FF }, 80 },
756 { { 0x2400, 0x243F }, 81 },
757 { { 0x2440, 0x245F }, 82 },
758 { { 0x2460, 0x24FF }, 83 },
759 { { 0x2500, 0x257F }, 84 },
760 { { 0x2580, 0x259F }, 85 },
761 { { 0x25A0, 0x25FF }, 86 },
762 { { 0x2600, 0x26FF }, 87 },
763 { { 0x2700, 0x27BF }, 88 },
764 { { 0x27C0, 0x27EF }, 89 },
765 { { 0x27F0, 0x27FF }, 90 },
766 { { 0x2800, 0x28FF }, 91 },
767 { { 0x2900, 0x297F }, 92 },
768 { { 0x2980, 0x29FF }, 93 },
769 { { 0x2A00, 0x2AFF }, 94 },
770 { { 0x2B00, 0x2BFF }, 95 },
771 { { 0x2C00, 0x2C5F }, 96 },
772 { { 0x2C60, 0x2C7F }, 97 },
773 { { 0x2C80, 0x2CFF }, 98 },
774 { { 0x2D00, 0x2D2F }, 99 },
775 { { 0x2D30, 0x2D7F }, 100 },
776 { { 0x2D80, 0x2DDF }, 101 },
777 { { 0x2DE0, 0x2DFF }, 102 },
778 { { 0x2E00, 0x2E7F }, 103 },
779 { { 0x2E80, 0x2EFF }, 104 },
780 { { 0x2F00, 0x2FDF }, 105 },
781 { { 0x2FF0, 0x2FFF }, 106 },
782 { { 0x3000, 0x303F }, 107 },
783 { { 0x3040, 0x309F }, 108 },
784 { { 0x30A0, 0x30FF }, 109 },
785 { { 0x3100, 0x312F }, 110 },
786 { { 0x3130, 0x318F }, 111 },
787 { { 0x3190, 0x319F }, 112 },
788 { { 0x31A0, 0x31BF }, 113 },
789 { { 0x31C0, 0x31EF }, 114 },
790 { { 0x31F0, 0x31FF }, 115 },
791 { { 0x3200, 0x32FF }, 116 },
792 { { 0x3300, 0x33FF }, 117 },
793 { { 0x3400, 0x4DBF }, 118 },
794 { { 0x4DC0, 0x4DFF }, 119 },
795 { { 0x4E00, 0x9FFF }, 120 },
796 { { 0xA000, 0xA48F }, 121 },
797 { { 0xA490, 0xA4CF }, 122 },
798 { { 0xA4D0, 0xA4FF }, 123 },
799 { { 0xA500, 0xA63F }, 124 },
800 { { 0xA640, 0xA69F }, 125 },
801 { { 0xA6A0, 0xA6FF }, 126 },
802 { { 0xA700, 0xA71F }, 127 },
803 { { 0xA720, 0xA7FF }, 128 },
804 { { 0xA800, 0xA82F }, 129 },
805 { { 0xA830, 0xA83F }, 130 },
806 { { 0xA840, 0xA87F }, 131 },
807 { { 0xA880, 0xA8DF }, 132 },
808 { { 0xA8E0, 0xA8FF }, 133 },
809 { { 0xA900, 0xA92F }, 134 },
810 { { 0xA930, 0xA95F }, 135 },
811 { { 0xA960, 0xA97F }, 136 },
812 { { 0xA980, 0xA9DF }, 137 },
813 { { 0xA9E0, 0xA9FF }, 138 },
814 { { 0xAA00, 0xAA5F }, 139 },
815 { { 0xAA60, 0xAA7F }, 140 },
816 { { 0xAA80, 0xAADF }, 141 },
817 { { 0xAAE0, 0xAAFF }, 142 },
818 { { 0xAB00, 0xAB2F }, 143 },
819 { { 0xAB30, 0xAB6F }, 144 },
820 { { 0xAB70, 0xABBF }, 145 },
821 { { 0xABC0, 0xABFF }, 146 },
822 { { 0xAC00, 0xD7AF }, 147 },
823 { { 0xD7B0, 0xD7FF }, 148 },
824 { { 0xD800, 0xDB7F }, 149 },
825 { { 0xDB80, 0xDBFF }, 150 },
826 { { 0xDC00, 0xDFFF }, 151 },
827 { { 0xE000, 0xF8FF }, 152 },
828 { { 0xF900, 0xFAFF }, 153 },
829 { { 0xFB00, 0xFB4F }, 154 },
830 { { 0xFB50, 0xFDFF }, 155 },
831 { { 0xFE00, 0xFE0F }, 156 },
832 { { 0xFE10, 0xFE1F }, 157 },
833 { { 0xFE20, 0xFE2F }, 158 },
834 { { 0xFE30, 0xFE4F }, 159 },
835 { { 0xFE50, 0xFE6F }, 160 },
836 { { 0xFE70, 0xFEFF }, 161 },
837 { { 0xFF00, 0xFFEF }, 162 },
838 { { 0xFFF0, 0xFFFF }, 163 },
839 { { 0x10000, 0x1007F }, 164 },
840 { { 0x10080, 0x100FF }, 165 },
841 { { 0x10100, 0x1013F }, 166 },
842 { { 0x10140, 0x1018F }, 167 },
843 { { 0x10190, 0x101CF }, 168 },
844 { { 0x101D0, 0x101FF }, 169 },
845 { { 0x10280, 0x1029F }, 170 },
846 { { 0x102A0, 0x102DF }, 171 },
847 { { 0x102E0, 0x102FF }, 172 },
848 { { 0x10300, 0x1032F }, 173 },
849 { { 0x10330, 0x1034F }, 174 },
850 { { 0x10350, 0x1037F }, 175 },
851 { { 0x10380, 0x1039F }, 176 },
852 { { 0x103A0, 0x103DF }, 177 },
853 { { 0x10400, 0x1044F }, 178 },
854 { { 0x10450, 0x1047F }, 179 },
855 { { 0x10480, 0x104AF }, 180 },
856 { { 0x104B0, 0x104FF }, 181 },
857 { { 0x10500, 0x1052F }, 182 },
858 { { 0x10530, 0x1056F }, 183 },
859 { { 0x10570, 0x105BF }, 184 },
860 { { 0x10600, 0x1077F }, 185 },
861 { { 0x10780, 0x107BF }, 186 },
862 { { 0x10800, 0x1083F }, 187 },
863 { { 0x10840, 0x1085F }, 188 },
864 { { 0x10860, 0x1087F }, 189 },
865 { { 0x10880, 0x108AF }, 190 },
866 { { 0x108E0, 0x108FF }, 191 },
867 { { 0x10900, 0x1091F }, 192 },
868 { { 0x10920, 0x1093F }, 193 },
869 { { 0x10980, 0x1099F }, 194 },
870 { { 0x109A0, 0x109FF }, 195 },
871 { { 0x10A00, 0x10A5F }, 196 },
872 { { 0x10A60, 0x10A7F }, 197 },
873 { { 0x10A80, 0x10A9F }, 198 },
874 { { 0x10AC0, 0x10AFF }, 199 },
875 { { 0x10B00, 0x10B3F }, 200 },
876 { { 0x10B40, 0x10B5F }, 201 },
877 { { 0x10B60, 0x10B7F }, 202 },
878 { { 0x10B80, 0x10BAF }, 203 },
879 { { 0x10C00, 0x10C4F }, 204 },
880 { { 0x10C80, 0x10CFF }, 205 },
881 { { 0x10D00, 0x10D3F }, 206 },
882 { { 0x10E60, 0x10E7F }, 207 },
883 { { 0x10E80, 0x10EBF }, 208 },
884 { { 0x10EC0, 0x10EFF }, 209 },
885 { { 0x10F00, 0x10F2F }, 210 },
886 { { 0x10F30, 0x10F6F }, 211 },
887 { { 0x10F70, 0x10FAF }, 212 },
888 { { 0x10FB0, 0x10FDF }, 213 },
889 { { 0x10FE0, 0x10FFF }, 214 },
890 { { 0x11000, 0x1107F }, 215 },
891 { { 0x11080, 0x110CF }, 216 },
892 { { 0x110D0, 0x110FF }, 217 },
893 { { 0x11100, 0x1114F }, 218 },
894 { { 0x11150, 0x1117F }, 219 },
895 { { 0x11180, 0x111DF }, 220 },
896 { { 0x111E0, 0x111FF }, 221 },
897 { { 0x11200, 0x1124F }, 222 },
898 { { 0x11280, 0x112AF }, 223 },
899 { { 0x112B0, 0x112FF }, 224 },
900 { { 0x11300, 0x1137F }, 225 },
901 { { 0x11400, 0x1147F }, 226 },
902 { { 0x11480, 0x114DF }, 227 },
903 { { 0x11580, 0x115FF }, 228 },
904 { { 0x11600, 0x1165F }, 229 },
905 { { 0x11660, 0x1167F }, 230 },
906 { { 0x11680, 0x116CF }, 231 },
907 { { 0x116D0, 0x116FF }, 232 },
908 { { 0x11700, 0x1174F }, 233 },
909 { { 0x11800, 0x1184F }, 234 },
910 { { 0x118A0, 0x118FF }, 235 },
911 { { 0x11900, 0x1195F }, 236 },
912 { { 0x119A0, 0x119FF }, 237 },
913 { { 0x11A00, 0x11A4F }, 238 },
914 { { 0x11A50, 0x11AAF }, 239 },
915 { { 0x11AB0, 0x11ABF }, 240 },
916 { { 0x11AC0, 0x11AFF }, 241 },
917 { { 0x11B00, 0x11B5F }, 242 },
918 { { 0x11C00, 0x11C6F }, 243 },
919 { { 0x11C70, 0x11CBF }, 244 },
920 { { 0x11D00, 0x11D5F }, 245 },
921 { { 0x11D60, 0x11DAF }, 246 },
922 { { 0x11EE0, 0x11EFF }, 247 },
923 { { 0x11F00, 0x11F5F }, 248 },
924 { { 0x11FB0, 0x11FBF }, 249 },
925 { { 0x11FC0, 0x11FFF }, 250 },
926 { { 0x12000, 0x123FF }, 251 },
927 { { 0x12400, 0x1247F }, 252 },
928 { { 0x12480, 0x1254F }, 253 },
929 { { 0x12F90, 0x12FFF }, 254 },
930 { { 0x13000, 0x1342F }, 255 },
931 { { 0x13430, 0x1345F }, 256 },
932 { { 0x14400, 0x1467F }, 257 },
933 { { 0x16800, 0x16A3F }, 258 },
934 { { 0x16A40, 0x16A6F }, 259 },
935 { { 0x16A70, 0x16ACF }, 260 },
936 { { 0x16AD0, 0x16AFF }, 261 },
937 { { 0x16B00, 0x16B8F }, 262 },
938 { { 0x16D40, 0x16D7F }, 263 },
939 { { 0x16E40, 0x16E9F }, 264 },
940 { { 0x16F00, 0x16F9F }, 265 },
941 { { 0x16FE0, 0x16FFF }, 266 },
942 { { 0x17000, 0x187FF }, 267 },
943 { { 0x18800, 0x18AFF }, 268 },
944 { { 0x18B00, 0x18CFF }, 269 },
945 { { 0x18D00, 0x18D7F }, 270 },
946 { { 0x1AFF0, 0x1AFFF }, 271 },
947 { { 0x1B000, 0x1B0FF }, 272 },
948 { { 0x1B100, 0x1B12F }, 273 },
949 { { 0x1B130, 0x1B16F }, 274 },
950 { { 0x1B170, 0x1B2FF }, 275 },
951 { { 0x1BC00, 0x1BC9F }, 276 },
952 { { 0x1BCA0, 0x1BCAF }, 277 },
953 { { 0x1CC00, 0x1CEBF }, 278 },
954 { { 0x1CF00, 0x1CFCF }, 279 },
955 { { 0x1D000, 0x1D0FF }, 280 },
956 { { 0x1D100, 0x1D1FF }, 281 },
957 { { 0x1D200, 0x1D24F }, 282 },
958 { { 0x1D2C0, 0x1D2DF }, 283 },
959 { { 0x1D2E0, 0x1D2FF }, 284 },
960 { { 0x1D300, 0x1D35F }, 285 },
961 { { 0x1D360, 0x1D37F }, 286 },
962 { { 0x1D400, 0x1D7FF }, 287 },
963 { { 0x1D800, 0x1DAAF }, 288 },
964 { { 0x1DF00, 0x1DFFF }, 289 },
965 { { 0x1E000, 0x1E02F }, 290 },
966 { { 0x1E030, 0x1E08F }, 291 },
967 { { 0x1E100, 0x1E14F }, 292 },
968 { { 0x1E290, 0x1E2BF }, 293 },
969 { { 0x1E2C0, 0x1E2FF }, 294 },
970 { { 0x1E4D0, 0x1E4FF }, 295 },
971 { { 0x1E5D0, 0x1E5FF }, 296 },
972 { { 0x1E7E0, 0x1E7FF }, 297 },
973 { { 0x1E800, 0x1E8DF }, 298 },
974 { { 0x1E900, 0x1E95F }, 299 },
975 { { 0x1EC70, 0x1ECBF }, 300 },
976 { { 0x1ED00, 0x1ED4F }, 301 },
977 { { 0x1EE00, 0x1EEFF }, 302 },
978 { { 0x1F000, 0x1F02F }, 303 },
979 { { 0x1F030, 0x1F09F }, 304 },
980 { { 0x1F0A0, 0x1F0FF }, 305 },
981 { { 0x1F100, 0x1F1FF }, 306 },
982 { { 0x1F200, 0x1F2FF }, 307 },
983 { { 0x1F300, 0x1F5FF }, 308 },
984 { { 0x1F600, 0x1F64F }, 309 },
985 { { 0x1F650, 0x1F67F }, 310 },
986 { { 0x1F680, 0x1F6FF }, 311 },
987 { { 0x1F700, 0x1F77F }, 312 },
988 { { 0x1F780, 0x1F7FF }, 313 },
989 { { 0x1F800, 0x1F8FF }, 314 },
990 { { 0x1F900, 0x1F9FF }, 315 },
991 { { 0x1FA00, 0x1FA6F }, 316 },
992 { { 0x1FA70, 0x1FAFF }, 317 },
993 { { 0x1FB00, 0x1FBFF }, 318 },
994 { { 0x20000, 0x2A6DF }, 319 },
995 { { 0x2A700, 0x2B73F }, 320 },
996 { { 0x2B740, 0x2B81F }, 321 },
997 { { 0x2B820, 0x2CEAF }, 322 },
998 { { 0x2CEB0, 0x2EBEF }, 323 },
999 { { 0x2EBF0, 0x2EE5F }, 324 },
1000 { { 0x2F800, 0x2FA1F }, 325 },
1001 { { 0x30000, 0x3134F }, 326 },
1002 { { 0x31350, 0x323AF }, 327 },
1003 { { 0xE0000, 0xE007F }, 328 },
1004 { { 0xE0100, 0xE01EF }, 329 },
1005 { { 0xF0000, 0xFFFFF }, 330 },
1006 { { 0x100000, 0x10FFFF }, 331 },
1007 };
1008