• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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