• 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<array>
8 #include <cstring>
9 #include <dirent.h>
10 #include <libgen.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <unistd.h>
14 
15 #ifdef SK_BUILD_FONT_MGR_FOR_OHOS
16 #include <parameters.h>
17 #endif
18 
19 #include "securec.h"
20 
21 #include "SkFontStyle.h"
22 #include "SkString.h"
23 
24 using namespace ErrorCode;
25 static const char* PRODUCT_DEFAULT_CONFIG = "/system/etc/productfontconfig.json";
26 
27 #ifdef SK_BUILD_FONT_MGR_FOR_OHOS
28     static const bool G_IS_HMSYMBOL_ENABLE =
29         (std::atoi(OHOS::system::GetParameter("persist.sys.graphic.hmsymbolcfg.enable", "1").c_str()) != 0);
30 #else
31     static const bool G_IS_HMSYMBOL_ENABLE = true;
32 #endif
33 
34 #if defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_WIN) or defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_MAC) or defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_LINUX)
35 static const char* OHOS_DEFAULT_CONFIG = "fontconfig.json";
36 /*! Constructor
37  * \param fontScanner the scanner to get the font information from a font file
38  * \param fname the full name of system font configuration document.
39  *     \n The default value is '/system/etc/fontconfig.json', if fname is given null
40  */
FontConfig_OHOS(const SkTypeface_FreeType::Scanner & fontScanner,const char * fname)41 FontConfig_OHOS::FontConfig_OHOS(const SkTypeface_FreeType::Scanner& fontScanner,
42     const char* fname)
43 {
44     int err = parseConfig(fname);
45     if (err != NO_ERROR) {
46         return;
47     }
48     scanFonts(fontScanner);
49     resetGenericValue();
50     resetFallbackValue();
51 }
52 #else
53 static const char* OHOS_DEFAULT_CONFIG = "/system/etc/fontconfig.json";
54 /*! Constructor
55  * \param fontScanner the scanner to get the font information from a font file
56  * \param fname the full name of system font configuration document.
57  *     \n The default value is '/system/etc/fontconfig.json', if fname is given null
58  */
FontConfig_OHOS(const SkTypeface_FreeType::Scanner & fontScanner,const char * fname)59 FontConfig_OHOS::FontConfig_OHOS(const SkTypeface_FreeType::Scanner& fontScanner,
60     const char* fname)
61 {
62     int err = checkProductFile(fname);
63     if (err != NO_ERROR) {
64         return;
65     }
66     scanFonts(fontScanner);
67     resetGenericValue();
68     resetFallbackValue();
69 }
70 #endif
71 
72 /*! To get the fallbackForMap
73  *  \return The reference of fallbackForMap
74  */
getFallbackForMap() const75 const FallbackForMap& FontConfig_OHOS::getFallbackForMap() const
76 {
77     return fallbackForMap;
78 }
79 
80 /*! To get the fallback set
81  *  \return The reference of fallbackSet
82  */
getFallbackSet() const83 const FallbackSet& FontConfig_OHOS::getFallbackSet() const
84 {
85     return fallbackSet;
86 }
87 
88 /*! To get the count of font style sets supported in the system
89  *  \return The count of font style sets in generic family
90  */
getFamilyCount() const91 int FontConfig_OHOS::getFamilyCount() const
92 {
93     return genericFamilySet.size();
94 }
95 
96 /*! To get the family name of the default font style set
97  *  \param[out] familyName a pointer of SkString object, to which the family value will be set.
98  *  \return The count of typeface in this font style set
99  *  \n Return -1, if there is no any font style set in the system.
100  */
getDefaultFamily(SkString * familyName) const101 int FontConfig_OHOS::getDefaultFamily(SkString* familyName) const
102 {
103     return getFamilyName(0, familyName);
104 }
105 
106 /*! To get the family name of a font style set
107  * \param index the index of a font style set in generic family
108  * \param[out] familyName a pointer of SkString object, to which the family value will be set
109  * \return The count of typeface in the font style set
110  * \n      Return -1, if the 'index' is out of range
111  */
getFamilyName(int index,SkString * familyName) const112 int FontConfig_OHOS::getFamilyName(int index, SkString* familyName) const
113 {
114     if (index < 0 || index >= this->getFamilyCount()) {
115         if (familyName) {
116             familyName->reset();
117         }
118         return -1;
119     }
120     if (familyName) {
121         *familyName = genericFamilySet[index]->familyName;
122     }
123     return genericFamilySet[index]->typefaceSet->size();
124 }
125 
126 /*! To get the count of a font style set
127  * \param styleIndex the index of a font style set
128  * \param isFallback to indicate the font style set is from generic family or fallback family
129  * \n                 false , the font style set is from generic family list
130  * \n                 true, the font style set is from fallback family list
131  * \return The count of typeface in the font style set
132  */
getTypefaceCount(int styleIndex,bool isFallback) const133 int FontConfig_OHOS::getTypefaceCount(int styleIndex, bool isFallback) const
134 {
135     if (styleIndex < 0) {
136         return -1;
137     }
138     if (isFallback) {
139         if ((unsigned int)styleIndex < fallbackSet.size()) {
140             return fallbackSet[styleIndex]->typefaceSet->size();
141         }
142     } else {
143         if ((unsigned int)styleIndex < genericFamilySet.size()) {
144             return genericFamilySet[styleIndex]->typefaceSet->size();
145         }
146     }
147     return -1;
148 }
149 
150 /*! To get a typeface
151  * \param styleIndex the index of a font style set
152  * \param index the index of a typeface in its style set
153  * \param isFallback false, the font style set is generic
154  * \n          true, the font style set is fallback
155  * \return The pointer of a typeface
156  * \n       Return null, if 'styleIndex' or 'index' is out of range
157  */
getTypeface(int styleIndex,int index,bool isFallback) const158 SkTypeface_OHOS* FontConfig_OHOS::getTypeface(int styleIndex, int index,
159     bool isFallback) const
160 {
161     if (styleIndex < 0 || index < 0 ||
162         (isFallback && (unsigned int)styleIndex >= fallbackSet.size()) ||
163         (!isFallback && (unsigned int)styleIndex >= genericFamilySet.size())) {
164         return nullptr;
165     }
166     if (isFallback) {
167         const TypefaceSet& tpSet = *(fallbackSet[styleIndex]->typefaceSet.get());
168         if ((unsigned int)index < tpSet.size()) {
169             return tpSet[index].get();
170         }
171     } else {
172         const TypefaceSet& tpSet = *(genericFamilySet[styleIndex]->typefaceSet.get());
173         if ((unsigned int)index < tpSet.size()) {
174             return tpSet[index].get();
175         }
176     }
177     return nullptr;
178 }
179 
180 /*! To get a typeface
181  * \param styleIndex the index a font style set
182  * \param style the font style to be matching
183  * \param isFallback false, the font style set is generic
184  * \n                true, the font style set is fallback
185  * \return An object of typeface whose font style is the closest matching to 'style'
186  * \n      Return null, if 'styleIndex' is out of range
187  */
getTypeface(int styleIndex,const SkFontStyle & style,bool isFallback) const188 SkTypeface_OHOS* FontConfig_OHOS::getTypeface(int styleIndex, const SkFontStyle& style,
189     bool isFallback) const
190 {
191     if (styleIndex < 0 ||
192         (isFallback && (unsigned int)styleIndex >= fallbackSet.size()) ||
193         (!isFallback && (unsigned int)styleIndex >= genericFamilySet.size())) {
194         return nullptr;
195     }
196     const TypefaceSet* pSet = nullptr;
197     if (isFallback) {
198         pSet = fallbackSet[styleIndex]->typefaceSet.get();
199     } else {
200         pSet = genericFamilySet[styleIndex]->typefaceSet.get();
201     }
202     sk_sp<SkTypeface_OHOS> tp = matchFontStyle(*pSet, style);
203     return tp.get();
204 }
205 
206 /*! To get the index of a font style set
207  *  \param familyName the family name of the font style set
208  *  \n     get the index of default font style set, if 'familyName' is null
209  *  \param[out] isFallback to tell if the family is from generic or fallback to the caller.
210  *  \n          isFallback is false, if the font style is from generic family list
211  *  \n          isFallback is true, if the font style is from fallback family list
212  *  \return The index of the font style set
213  *  \n      Return -1, if 'familyName' is not found in the system
214  */
getStyleIndex(const char * familyName,bool & isFallback) const215 int FontConfig_OHOS::getStyleIndex(const char* familyName, bool& isFallback) const
216 {
217     if (familyName == nullptr) {
218         isFallback = false;
219         return 0;
220     }
221 
222     std::lock_guard<std::mutex> lock(fontMutex);
223     if (genericNames.count() == 0) {
224         return -1;
225     }
226 
227     SkString fname(familyName);
228     int* p = genericNames.find(fname);
229     if (p) {
230         isFallback = false;
231         return *p;
232     } else {
233         if (fallbackNames.count() == 0) {
234             return -1;
235         }
236 
237         p = fallbackNames.find(fname);
238         if (p) {
239             isFallback = true;
240             return *p;
241         }
242     }
243     return -1;
244 }
245 
246 /*! Find the closest matching typeface
247  * \param typefaceSet a typeface set belonging to the same font style set
248  * \param pattern the font style to be matching
249  * \return The typeface object which is the closest matching to 'pattern'
250  * \n      Return null, if the count of typeface is 0
251  */
matchFontStyle(const TypefaceSet & typefaceSet,const SkFontStyle & pattern)252 sk_sp<SkTypeface_OHOS> FontConfig_OHOS::matchFontStyle(const TypefaceSet& typefaceSet,
253     const SkFontStyle& pattern)
254 {
255     int count = typefaceSet.size();
256     if (count == 1) {
257         return typefaceSet[0];
258     }
259     sk_sp<SkTypeface_OHOS> res = nullptr;
260     uint32_t minDiff = 0xFFFFFFFF;
261     for (int i = 0; i < count; i++) {
262         const SkFontStyle& fontStyle = typefaceSet[i]->fontStyle();
263         uint32_t diff = getFontStyleDifference(pattern, fontStyle);
264         if (diff < minDiff) {
265             minDiff = diff;
266             res = typefaceSet[i];
267         }
268     }
269     return res;
270 }
271 
272 /*! To get the difference between a font style and the matching font style
273  * \param dstStyle the style to be matching
274  * \param srcStyle a font style
275  * \return The difference value of a specified style with the matching style
276  */
getFontStyleDifference(const SkFontStyle & dstStyle,const SkFontStyle & srcStyle)277 uint32_t FontConfig_OHOS::getFontStyleDifference(const SkFontStyle& dstStyle,
278     const SkFontStyle& srcStyle)
279 {
280     int normalWidth = SkFontStyle::kNormal_Width;
281     int dstWidth = dstStyle.width();
282     int srcWidth = srcStyle.width();
283 
284     uint32_t widthDiff = 0;
285     // The maximum font width is kUltraExpanded_Width i.e. '9'.
286     // If dstWidth <= kNormal_Width (5), first check narrower values, then wider values.
287     // If dstWidth > kNormal_Width, first check wider values, then narrower values.
288     // When dstWidth and srcWidth are at different side of kNormal_Width,
289     // the width difference between them should be more than 5 (9/2+1)
290     if (dstWidth <= normalWidth) {
291         if (srcWidth <= dstWidth) {
292             widthDiff = dstWidth - srcWidth;
293         } else {
294             widthDiff = srcWidth - dstWidth + 5;
295         }
296     } else {
297         if (srcWidth >= dstWidth) {
298             widthDiff = srcWidth - dstWidth;
299         } else {
300             widthDiff = dstWidth - srcWidth + 5;
301         }
302     }
303 
304     int diffSlantValue[3][3] = {
305         {0, 2, 1},
306         {2, 0, 1},
307         {2, 1, 0}
308     };
309     uint32_t slantDiff = diffSlantValue[dstStyle.slant()][srcStyle.slant()];
310 
311     int dstWeight = dstStyle.weight();
312     int srcWeight = srcStyle.weight();
313     uint32_t weightDiff = 0;
314 
315     // The maximum weight is kExtraBlack_Weight (1000), when dstWeight and srcWeight are at the different
316     // side of kNormal_Weight, the weight difference between them should be more than 500 (1000/2)
317     if ((dstWeight == SkFontStyle::kNormal_Weight && srcWeight == SkFontStyle::kMedium_Weight) ||
318         (dstWeight == SkFontStyle::kMedium_Weight && srcWeight == SkFontStyle::kNormal_Weight)) {
319         weightDiff = 50;
320     } else if (dstWeight <= SkFontStyle::kNormal_Weight) {
321         if (srcWeight <= dstWeight) {
322             weightDiff = dstWeight - srcWeight;
323         } else {
324             weightDiff = srcWeight - dstWeight + 500;
325         }
326     } else if (dstWeight > SkFontStyle::kNormal_Weight) {
327         if (srcWeight >= dstWeight) {
328             weightDiff = srcWeight - dstWeight;
329         } else {
330             weightDiff = dstWeight - srcWeight + 500;
331         }
332     }
333     // The first 2 bytes to save weight difference, the third byte to save slant difference,
334     // and the fourth byte to save width difference
335     uint32_t diff = (widthDiff << 24) + (slantDiff << 16) + weightDiff;
336     return diff;
337 }
338 
339 /*! To get the data of font configuration file
340  * \param fname the full name of the font configuration file
341  * \param[out] size the size of data returned to the caller
342  * \return The pointer of content of the file
343  * \note The returned pointer should be freed by the caller
344  */
getFileData(const char * fname,int & size)345 char* FontConfig_OHOS::getFileData(const char* fname, int& size)
346 {
347     FILE* fp = fopen(fname, "r");
348     if (fp == nullptr) {
349         return nullptr;
350     }
351     fseek(fp, 0L, SEEK_END);
352     size = ftell(fp) + 1;
353     rewind(fp);
354     void* data = malloc(size);
355     if (data == nullptr) {
356         fclose(fp);
357         return nullptr;
358     }
359     memset_s(data, size, 0, size);
360     (void) fread(data, size, 1, fp);
361     fclose(fp);
362     return (char*)data;
363 }
364 
365 /*! parse the system font configuration document
366  * \param fname the full name of the font configuration document
367  * \return NO_ERROR successful
368  * \return ERROR_CONFIG_NOT_FOUND config document is not found
369  * \return ERROR_CONFIG_FORMAT_NOT_SUPPORTED config document format is not supported
370  * \return ERROR_CONFIG_INVALID_VALUE_TYPE wrong type of value in the configuration
371  */
parseConfig(const char * fname)372 int FontConfig_OHOS::parseConfig(const char* fname)
373 {
374     if (fname == nullptr) {
375         fname = OHOS_DEFAULT_CONFIG;
376     }
377     Json::Value root;
378     int err = checkConfigFile(fname, root);
379     if (err != NO_ERROR) {
380         return err;
381     }
382     // "fontdir" - optional, the data type should be string
383     const char* key = "fontdir";
384     if (root.isMember(key)) {
385         if (root[key].isArray()) {
386             parseFontDir(fname, root[key]);
387         } else {
388             return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key);
389         }
390     }
391     // "generic", "fallback" - necessary, the data type should be array
392     const char* keys[] = {"generic", "fallback", nullptr};
393     int index = 0;
394     while (true) {
395         if (keys[index] == nullptr) {
396             break;
397         }
398         key = keys[index++];
399         if (!root.isMember(key)) {
400             return logErrInfo(ERROR_CONFIG_MISSING_TAG, key);
401         } else if (!root[key].isArray()) {
402             return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key, Json::arrayValue, root[key].type());
403         }
404         const Json::Value& arr = root[key];
405         for (unsigned int i = 0; i < arr.size(); i++) {
406             if (arr[i].isObject()) {
407                 if (!strcmp(key, "generic")) {
408                     parseGeneric(arr[i]);
409                 } else if (!strcmp(key, "fallback")) {
410                     parseFallback(arr[i]);
411                 }
412             } else {
413                 SkString errKey;
414                 errKey.appendf("%s#%d", key, i + 1);
415                 (void) logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, errKey.c_str(),
416                     Json::objectValue, arr[i].type());
417             }
418         }
419     }
420     root.clear();
421     return NO_ERROR;
422 }
423 
424 /*! check the system font configuration document
425  * \param fname the full name of the font configuration document
426  * \return NO_ERROR successful
427  * \return ERROR_CONFIG_NOT_FOUND config document is not found
428  * \return ERROR_CONFIG_FORMAT_NOT_SUPPORTED config document format is not supported
429  */
checkConfigFile(const char * fname,Json::Value & root)430 int FontConfig_OHOS::checkConfigFile(const char* fname, Json::Value& root)
431 {
432     int size = 0;
433     char* data = getFileData(fname, size);
434     if (data == nullptr) {
435         return logErrInfo(ERROR_CONFIG_NOT_FOUND, fname);
436     }
437     JSONCPP_STRING errs;
438     Json::CharReaderBuilder charReaderBuilder;
439     std::unique_ptr<Json::CharReader> jsonReader(charReaderBuilder.newCharReader());
440     bool isJson = jsonReader->parse(data, data + size, &root, &errs);
441     free((void*)data);
442     data = nullptr;
443 
444     if (!isJson || !errs.empty()) {
445         return logErrInfo(ERROR_CONFIG_FORMAT_NOT_SUPPORTED, fname);
446     }
447     return NO_ERROR;
448 }
449 #if ENABLE_DEBUG
450 /*! To print out the font information
451  * \param font the font object to be printed
452  */
dumpFont(const FontInfo & font) const453 void FontConfig_OHOS::dumpFont(const FontInfo& font) const
454 {
455     LOGI("name=%s, family=%s, weight=%d, width=%d, slant=%d, index=%d",
456         font.fname.c_str(), font.familyName.c_str(), font.style.weight(), font.style.width(), font.style.slant(),
457         font.index);
458     int count = font.axisSet.axis.size();
459     if (count > 0) {
460         SkString str;
461         for (unsigned int i = 0; i < count; i++) {
462             str.appendU32(SkFixedFloorToInt(font.axisSet.axis[i]));
463             if (i < count - 1) {
464                 str.append(",");
465             }
466         }
467         LOGI("axis={%s}\n", str.c_str());
468     }
469 }
470 
471 /*! To print out the information of generic font style set
472  */
dumpGeneric() const473 void FontConfig_OHOS::dumpGeneric() const
474 {
475     LOGI("\n");
476     for (unsigned int i = 0; i < genericFamilySet.size(); i++) {
477         LOGI("[%d] familyName : %s - %d\n", i, genericFamilySet[i]->familyName.c_str(),
478             static_cast<int>(genericFamilySet[i]->typefaceSet->size()));
479         for (int j = 0; j < genericFamilySet[i]->typefaceSet->size(); j++) {
480             if ((*(genericFamilySet[i]->typefaceSet))[j].get()) {
481                 const FontInfo* font = (*(genericFamilySet[i]->typefaceSet))[j]->getFontInfo();
482                 if (font) {
483                     dumpFont(*font);
484                 } else {
485                     LOGE("font [%d] is null\n", j);
486                 }
487             } else {
488                 LOGE("typefeace [%d] is null\n", j);
489             }
490         }
491     }
492 }
493 
494 /*! To print out the information of fallback font style set
495  */
dumpFallback() const496 void FontConfig_OHOS::dumpFallback() const
497 {
498     LOGI("\n");
499     int count = 0;
500     fallbackForMap.foreach([this, &count](const SkString& key,
501         const FallbackSetPos& setIndex) {
502         LOGI("[%d] family : %s - %d\n", count++, key.c_str(), setIndex.count);
503         for (unsigned int i = setIndex.index; i < setIndex.index + setIndex.count; i++) {
504             const TypefaceSet& tpSet = *(fallbackSet[i]->typefaceSet.get());
505             LOGI("[%s] - %d\n", fallbackSet[i]->familyName.c_str(), static_cast<int>(tpSet.size()));
506 
507             for (unsigned int j = 0; j < tpSet.size(); j++) {
508                 const FontInfo* font = tpSet[j]->getFontInfo();
509                 if (font) {
510                     this->dumpFont(*font);
511                 } else {
512                     LOGE("font [%d] is null\n", j);
513                 }
514             }
515         }
516     });
517 }
518 #endif
519 
520 /*! To parse 'fontdir' attribute
521  * \param root the root node of 'fontdir'
522  * \return NO_ERROR successful
523  * \return ERROR_CONFIG_INVALID_VALUE_TYPE invalid value type
524  */
parseFontDir(const char * fname,const Json::Value & root)525 int FontConfig_OHOS::parseFontDir(const char* fname, const Json::Value& root)
526 {
527     for (unsigned int i = 0; i < root.size(); i++) {
528         if (root[i].isString()) {
529             const char* dir;
530 #if defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_WIN) or defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_MAC) or \
531     defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_LINUX)
532             if (strcmp(fname, OHOS_DEFAULT_CONFIG) == 0) {
533                 dir = strcmp(root[i].asCString(), "/system/fonts/") ? root[i].asCString() : "fonts";
534             } else {
535                 dir = strcmp(root[i].asCString(), "/system/fonts/") ?
536                     root[i].asCString() : "../../../../hms/previewer/resources/fonts";
537             }
538 #else
539             dir = root[i].asCString();
540 #endif
541             fontDirSet.emplace_back(SkString(dir));
542         } else {
543             SkString text;
544             text.appendf("fontdir#%d", i + 1);
545             return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, text.c_str(), Json::stringValue, root[i].type());
546         }
547     }
548     return NO_ERROR;
549 }
550 
551 /*! To parse an item of 'generic' family
552  * \param root the root node of an item in 'generic' list
553  * \return NO_ERROR successful
554  * \return ERROR_CONFIG_INVALID_VALUE_TYPE invalid value type for an attribute
555  * \return ERROR_CONFIG_MISSING_TAG missing tag of 'family' or 'alias'
556  */
parseGeneric(const Json::Value & root)557 int FontConfig_OHOS::parseGeneric(const Json::Value& root)
558 {
559     // "family" - necessary, the data type should be String
560     const char* key = "family";
561     if (!root.isMember(key)) {
562         return logErrInfo(ERROR_CONFIG_MISSING_TAG, key);
563     } else if (!root[key].isString()) {
564         return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key, Json::stringValue, root[key].type());
565     }
566     SkString familyName = SkString(root[key].asCString());
567     // "alias" - necessary, the data type should be Array
568     if (!root.isMember("alias")) {
569         return logErrInfo(ERROR_CONFIG_MISSING_TAG, "alias");
570     }
571     // "adjust", "variation" - optional
572     const char* tags[] = {"alias", "adjust", "variations", "index"};
573     std::vector<AliasInfo> aliasSet;
574     std::vector<AdjustInfo> adjustSet;
575     std::vector<VariationInfo> variationSet;
576     for (unsigned int i = 0; i < sizeof(tags) / sizeof(char*); i++) {
577         key = tags[i];
578         if (!root.isMember(key)) {
579             continue;
580         }
581         if (root[key].isArray()) {
582             if (!strcmp(key, "index")) {
583                 parseTtcIndex(root[key], familyName);
584                 continue;
585             }
586             const Json::Value& arr = root[key];
587             for (unsigned int j = 0; j < arr.size(); j++) {
588                 if (arr[j].isObject()) {
589                     if (!strcmp(key, "alias")) {
590                         parseAlias(arr[j], aliasSet);
591                     } else if (!strcmp(key, "adjust")) {
592                         parseAdjust(arr[j], adjustSet);
593                     } else {
594                         parseVariation(arr[j], variationSet);
595                     }
596                 } else {
597                     SkString text;
598                     text.appendf("%s#%d", key, j + 1);
599                     (void) logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, text.c_str(), Json::objectValue,
600                         arr[j].type());
601                 }
602             }
603         } else {
604             (void) logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key, Json::arrayValue, root[key].type());
605         }
606         if (root.size() == 2) {
607             break;
608         }
609     }
610     if (aliasSet.size()) {
611         aliasMap.set(SkString(familyName), aliasSet);
612     }
613     if (adjustSet.size()) {
614         adjustMap.set(SkString(familyName), adjustSet);
615     }
616     if (variationSet.size()) {
617         variationMap.set(SkString(familyName), variationSet);
618     }
619     return NO_ERROR;
620 }
621 
622 /*! To parse an item of 'alias' attribute
623  * \param root the root node of an item in an 'alias' list
624  * \param[out] aliasSet the value of AliasInfo will be written to and returned to the caller
625  * \return NO_ERROR successful
626  * \return ERROR_CONFIG_INVALID_VALUE_TYPE invalid value type for an attribute
627  * \return ERROR_CONFIG_MISSING_TAG missing tag of alias name
628  */
parseAlias(const Json::Value & root,std::vector<AliasInfo> & aliasSet)629 int FontConfig_OHOS::parseAlias(const Json::Value& root, std::vector<AliasInfo>& aliasSet)
630 {
631     if (root.empty()) {
632         return logErrInfo(ERROR_CONFIG_MISSING_TAG, "generic-alias-name");
633     }
634     Json::Value::Members members = root.getMemberNames();
635     const char* key = members[0].c_str();
636     if (!root[key].isInt()) {
637         return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, "generic-alias-weight",
638             Json::intValue, root[key].type());
639     }
640 
641     SkString aliasName = SkString(key);
642     int weight = root[key].asInt();
643     std::unique_ptr<GenericFamily> genericFamily = std::make_unique<GenericFamily>();
644     genericFamily->familyName = SkString(key);
645     if (aliasSet.size() == 0 || weight > 0) {
646         genericFamily->typefaceSet = std::make_shared<TypefaceSet>();
647     } else {
648         int index = aliasSet[0].pos;
649         genericFamily->typefaceSet = genericFamilySet[index]->typefaceSet;
650     }
651     genericNames.set(SkString(genericFamily->familyName), genericFamilySet.size());
652 
653     AliasInfo info = {static_cast<int>(genericFamilySet.size()), weight};
654     aliasSet.emplace_back(std::move(info));
655     genericFamilySet.emplace_back(std::move(genericFamily));
656     return NO_ERROR;
657 }
658 
659 /*! To parse an item of 'adjust' attribute
660  * \param root the root node of an item in an 'adjust' list
661  * \param[out] adjustSet the value of AdjustInfo will be written to and returned to the caller
662  * \return NO_ERROR successful
663  * \return ERROR_CONFIG_INVALID_VALUE_TYPE invalid value type for an attribute
664  * \return ERROR_CONFIG_MISSING_TAG missing tag of 'weight' or 'to'
665  */
parseAdjust(const Json::Value & root,std::vector<AdjustInfo> & adjustSet)666 int FontConfig_OHOS::parseAdjust(const Json::Value& root, std::vector<AdjustInfo>& adjustSet)
667 {
668     const char* tags[] = {"weight", "to"};
669     int values[2]; // value[0] - to save 'weight', value[1] - to save 'to'
670     for (unsigned int i = 0; i < sizeof(tags) / sizeof(char*); i++) {
671         const char* key = tags[i];
672         if (!root.isMember(key)) {
673             return logErrInfo(ERROR_CONFIG_MISSING_TAG, key);
674         } else if (!root[key].isInt()) {
675             return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key,
676                 Json::intValue, root[key].type());
677         } else {
678             values[i] = root[key].asInt();
679         }
680     }
681     AdjustInfo info = {values[0], values[1]};
682     adjustSet.push_back(info);
683     return NO_ERROR;
684 }
685 
686 /*! To parse an item of 'fallback' attribute
687  * \param root the root node of an item in 'fallback' list
688  * \return NO_ERROR successful
689  * \return ERROR_CONFIG_INVALID_VALUE_TYPE invalid value type for an attribute
690  * \return ERROR_CONFIG_MISSING_TAG missing tag of fallbackFor
691  */
parseFallback(const Json::Value & root)692 int FontConfig_OHOS::parseFallback(const Json::Value& root)
693 {
694     if (root.empty()) {
695         return logErrInfo(ERROR_CONFIG_MISSING_TAG, "fallback-fallbackFor");
696     }
697     Json::Value::Members members = root.getMemberNames();
698     const char* key = members[0].c_str();
699     if (!root[key].isArray()) {
700         return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, "fallback-items",
701             Json::arrayValue, root[key].type());
702     }
703     unsigned int startPos = fallbackSet.size();
704     SkString fallbackFor = SkString(key);
705     const Json::Value& fallbackArr = root[key];
706     for (unsigned int i = 0; i < fallbackArr.size(); i++) {
707         if (!fallbackArr[i].isObject()) {
708             SkString text;
709             text.appendf("fallback-%s#%d", key, i + 1);
710             (void) logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, text.c_str(), Json::objectValue,
711                 fallbackArr[i].type());
712             continue;
713         }
714         parseFallbackItem(fallbackArr[i]);
715     }
716     FallbackSetPos setPos = {startPos, (unsigned int)(fallbackSet.size() - startPos)};
717     fallbackForMap.set(fallbackFor, setPos);
718     return NO_ERROR;
719 }
720 
721 /*! To parse an item of fallback family
722  * \param root the root node of a fallback item
723  * \return NO_ERROR successful
724  * \return ERROR_CONFIG_INVALID_VALUE_TYPE invalid value type for an attribute
725  * \return ERROR_CONFIG_MISSING_TAG missing tag of language
726  */
parseFallbackItem(const Json::Value & root)727 int FontConfig_OHOS::parseFallbackItem(const Json::Value& root)
728 {
729     if (root.empty()) {
730         return logErrInfo(ERROR_CONFIG_MISSING_TAG, "fallback-item-lang");
731     }
732     Json::Value::Members members = root.getMemberNames();
733     const char* key = nullptr;
734     bool hasIndex = false;
735     bool hasVariations = false;
736     for (unsigned int i = 0; i < members.size(); i++) {
737         if (members[i] == "variations") {
738             hasVariations = true;
739         } else if (members[i] == "index") {
740             hasIndex = true;
741         } else {
742             key = members[i].c_str();
743         }
744     }
745     if (key == nullptr) {
746         return logErrInfo(ERROR_CONFIG_MISSING_TAG, "fallback-item-lang");
747     }
748     if (!root[key].isString()) {
749         return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, "fallback-item-family",
750             Json::stringValue, root[key].type());
751     }
752     SkString lang = SkString(key);
753     SkString familyName = SkString(root[key].asCString());
754     if (hasVariations) {
755         key = "variations";
756         if (root[key].isArray()) {
757             const Json::Value& varArr = root[key];
758             std::vector<VariationInfo> variationSet;
759             for (unsigned int i = 0; i < varArr.size(); i++) {
760                 if (varArr[i].isObject()) {
761                     parseVariation(varArr[i], variationSet);
762                 } else {
763                     SkString text = SkString("variations#");
764                     text.appendU32(i + 1);
765                     (void) logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, text.c_str(),
766                         Json::objectValue, varArr[i].type());
767                 }
768             }
769             if (variationSet.size()) {
770                 variationMap.set(SkString(familyName), variationSet);
771             }
772         } else {
773             (void) logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key, Json::arrayValue,
774                 root[key].type());
775         }
776     }
777     if (hasIndex) {
778         key = "index";
779         if (root[key].isArray()) {
780             parseTtcIndex(root[key], familyName);
781         } else {
782             (void) logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key, Json::arrayValue, root[key].type());
783         }
784     }
785     std::unique_ptr<FallbackInfo> fallback = std::make_unique<FallbackInfo>();
786     fallback->familyName = familyName;
787     fallback->langs = lang;
788     fallback->typefaceSet = std::make_shared<TypefaceSet>();
789     fallbackNames.set(SkString(familyName), fallbackSet.size());
790     fallbackSet.emplace_back(std::move(fallback));
791     return NO_ERROR;
792 }
793 
794 /*! To parse an item of 'variations' attribute
795  * \param root the root node of an item in 'variations' list
796  * \param[out] variationSet the value of VariationInfo is written to and returned to the caller
797  * \return NO_ERROR successful
798  * \return ERROR_CONFIG_INVALID_VALUE_TYPE invalid value type for an attribute
799  * \return ERROR_CONFIG_MISSING_TAG missing tag of 'weight' or 'wght'
800  */
parseVariation(const Json::Value & root,std::vector<VariationInfo> & variationSet)801 int FontConfig_OHOS::parseVariation(const Json::Value& root, std::vector<VariationInfo>& variationSet)
802 {
803     const char* key = nullptr;
804     const char* tags[] = {"wght", "wdth", "slnt", "weight", "width", "slant"};
805     VariationInfo info;
806     for (unsigned int i = 0; i < sizeof(tags) / sizeof(char*); i++) {
807         key = tags[i];
808         if ((!strcmp(key, "wght") || !strcmp(key, "weight")) &&
809             !root.isMember(key)) {
810             return logErrInfo(ERROR_CONFIG_MISSING_TAG, key);
811         }
812         if (!root.isMember(key)) {
813             continue;
814         }
815         if (!strcmp(key, "weight")) {
816             if (!root[key].isInt()) {
817                 return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key, Json::intValue, root[key].type());
818             }
819             info.weight = root[key].asInt();
820         } else if (!strcmp(key, "width")) {
821             if (!root[key].isInt()) {
822                 return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key, Json::intValue, root[key].type());
823             }
824             info.width = root[key].asInt();
825         } else if (!strcmp(key, "slant")) {
826             if (!root[key].isString()) {
827                 return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key, Json::stringValue, root[key].type());
828             }
829             const char* str = root[key].asCString();
830             if (!strcmp(str, "normal")) {
831                 info.slant = static_cast<int>(SkFontStyle::kUpright_Slant);
832             } else if (!strcmp(str, "italic")) {
833                 info.slant = static_cast<int>(SkFontStyle::kItalic_Slant);
834             } else if (!strcmp(str, "oblique")) {
835                 info.slant = static_cast<int>(SkFontStyle::kOblique_Slant);
836             }
837         } else {
838             if (!root[key].isNumeric()) {
839                 return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key, Json::realValue, root[key].type());
840             }
841             Coordinate axis;
842             axis.axis = SkSetFourByteTag(key[0], key[1], key[2], key[3]);
843             axis.value = root[key].asFloat();
844             info.axis.emplace_back(axis);
845         }
846     }
847     variationSet.emplace_back(info);
848     return NO_ERROR;
849 }
850 
851 /*! To parse  'index' attribute
852  * \param root the root node of 'index' attribute
853  * \param familyName the name of the family which the root node belongs to
854  * \return NO_ERROR successful
855  * \return ERROR_CONFIG_INVALID_VALUE_TYPE invalid value type for an attribute
856  */
parseTtcIndex(const Json::Value & root,const SkString & familyName)857 int FontConfig_OHOS::parseTtcIndex(const Json::Value& root, const SkString& familyName)
858 {
859     unsigned int keyCount = 2; // the value of 'index' is an array with 2 items.
860     if (root.size() == keyCount && root[0].isString() && root[1].isNumeric()) {
861         TtcIndexInfo item = { SkString(root[0].asCString()), root[1].asInt() };
862         if (item.ttcIndex != 0 && ttcIndexMap.find(item.familyName) == nullptr) {
863             ttcIndexMap.set(SkString(item.familyName), {SkString(item.familyName), 0});
864         }
865         ttcIndexMap.set(SkString(familyName), item);
866     } else {
867         int ret = ERROR_CONFIG_INVALID_VALUE_TYPE;
868         SkString text;
869         const char* key = "index";
870         if (root.size() != keyCount) {
871             text.appendf("%s#0", key);
872             errSet.emplace_back(ret, text.c_str());
873             LOGE("%s : '%s' size should be 2, but here it's %d\n", errToString(ret), key, root.size());
874             return ret;
875         } else if (!root[0].isString()) {
876             text.appendf("%s#1", key);
877             return logErrInfo(ret, text.c_str(), Json::stringValue, root[0].type());
878         } else {
879             text.appendf("%s#2", key);
880             return logErrInfo(ret, text.c_str(), Json::intValue, root[1].type());
881         }
882     }
883     return NO_ERROR;
884 }
885 
886 /*! To get the axis value and set to 'font'
887  * \param axisDefs the axis ranges of a font
888  * \param variation the variation data from which axis values are generated
889  * \param[out] font the axis values will be written to and returned to the caller
890  */
getAxisValues(const AxisDefinitions & axisDefs,const VariationInfo & variation,FontInfo & font) const891 void FontConfig_OHOS::getAxisValues(const AxisDefinitions& axisDefs,
892     const VariationInfo& variation, FontInfo& font) const
893 {
894     SkFontArguments::VariationPosition position;
895     position.coordinateCount = variation.axis.size();
896     position.coordinates = variation.axis.data();
897 
898     int count = axisDefs.count();
899     SkFixed axisValues[count];
900     SkTypeface_FreeType::Scanner::computeAxisValues(axisDefs, position,
901         axisValues, font.familyName);
902     font.axisSet.axis.clear();
903     font.axisSet.range.clear();
904     for (int i = 0; i < count; i++) {
905         font.axisSet.axis.emplace_back(axisValues[i]);
906         font.axisSet.range.emplace_back(axisDefs[i]);
907     }
908 }
909 
910 /*! To insert a ttc font into a font style set
911  * \param count the count of typeface in a ttc font
912  * \param font an object of the FontInfo with font information
913  * \return true, if the font is a ttc font and added to corresponding font style set
914  * \return false, if the font is not a ttc font
915  */
insertTtcFont(int count,FontInfo & font)916 bool FontConfig_OHOS::insertTtcFont(int count, FontInfo& font)
917 {
918     bool ret = false;
919     ttcIndexMap.foreach([this, count, &font, &ret]
920         (const SkString& familyName, TtcIndexInfo* info) {
921         if (info->familyName == font.familyName && info->ttcIndex < count) {
922             SkString specifiedName;
923             TypefaceSet* tpSet = this->getTypefaceSet(familyName, specifiedName);
924             if (tpSet) {
925                 FontInfo newFont(font);
926                 newFont.familyName = familyName;
927                 newFont.index = info->ttcIndex;
928                 sk_sp<SkTypeface_OHOS> typeface = sk_make_sp<SkTypeface_OHOS>(specifiedName, newFont);
929                 tpSet->push_back(std::move(typeface));
930                 ret = true;
931             }
932         }
933     });
934     return ret;
935 }
936 
937 /*! To insert a variable font into a font style set
938  * \param axisDefs the axis ranges of a variable font
939  * \param font an object of the FontInfo with font information
940  * \return true, if the font is a variable and some typefaces are added to the corresponding font style set
941  * \return false, if the font is not variable
942  */
insertVariableFont(const AxisDefinitions & axisDefs,FontInfo & font)943 bool FontConfig_OHOS::insertVariableFont(const AxisDefinitions& axisDefs, FontInfo& font)
944 {
945     const SkString& key = font.familyName;
946     if (variationMap.find(key) == nullptr || axisDefs.count() == 0) {
947         return false;
948     }
949     SkString specifiedName;
950     TypefaceSet* tpSet = getTypefaceSet(key, specifiedName);
951     if (tpSet == nullptr) {
952         return false;
953     }
954     const std::vector<VariationInfo>& variationSet = *(variationMap.find(key));
955     for (unsigned int i = 0; i < variationSet.size(); i++) {
956         FontInfo newFont(font);
957         getAxisValues(axisDefs, variationSet[i], newFont);
958         int width = font.style.width();
959         SkFontStyle::Slant slant = font.style.slant();
960         if (variationSet[i].width != -1) {
961             width = variationSet[i].width;
962         }
963         if (variationSet[i].slant != -1) {
964             slant = (SkFontStyle::Slant) variationSet[i].slant;
965         }
966         newFont.style = SkFontStyle(variationSet[i].weight, width, slant);
967         sk_sp<SkTypeface_OHOS> typeface = sk_make_sp<SkTypeface_OHOS>(specifiedName, newFont);
968         tpSet->push_back(std::move(typeface));
969     }
970     return true;
971 }
972 
973 /*! To get the typeface set of a font style set
974  * \param familyName the family name of a font style set
975  * \param[out] specifiedName the specified family name of a font style set returned to the caller
976  * \return The object of typeface set
977  * \n      Return null, if the family name is not found in the system
978  */
getTypefaceSet(const SkString & familyName,SkString & specifiedName) const979 TypefaceSet* FontConfig_OHOS::getTypefaceSet(const SkString& familyName,
980     SkString& specifiedName) const
981 {
982     std::lock_guard<std::mutex> lock(fontMutex);
983     if (aliasMap.find(familyName) != nullptr) {
984         const std::vector<AliasInfo>& aliasSet = *(aliasMap.find(familyName));
985         if (aliasSet.size()) {
986             int index = aliasSet[0].pos;
987             specifiedName = genericFamilySet[index]->familyName;
988             return genericFamilySet[index]->typefaceSet.get();
989         }
990     } else if (fallbackNames.find(familyName) != nullptr) {
991         int index = *(fallbackNames.find(familyName));
992         return fallbackSet[index]->typefaceSet.get();
993     }
994     return nullptr;
995 }
996 
997 /*! To load font information from a font file
998  * \param scanner a scanner used to parse the font file
999  * \param fname the full name of a font file
1000  * \return NO_ERROR successful
1001  * \return ERROR_FONT_NOT_EXIST font file is not exist
1002  * \return ERROR_FONT_INVALID_STREAM the stream is not recognized
1003  */
loadFont(const SkTypeface_FreeType::Scanner & scanner,const char * fname)1004 int FontConfig_OHOS::loadFont(const SkTypeface_FreeType::Scanner& scanner, const char* fname)
1005 {
1006     std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(fname);
1007     int count = 1;
1008     SkTypeface_FreeType::Scanner::AxisDefinitions axisDefs;
1009     FontInfo font(fname, 0);
1010     if (stream == nullptr ||
1011         scanner.recognizedFont(stream.get(), &count) == false ||
1012         scanner.scanFont(stream.get(), 0, &font.familyName, &font.style,
1013             &font.isFixedWidth, &axisDefs) == false) {
1014         int err = NO_ERROR;
1015         if (stream == nullptr) {
1016             err = ERROR_FONT_NOT_EXIST;
1017         } else {
1018             err = ERROR_FONT_INVALID_STREAM;
1019         }
1020         LOGE("%s : %s\n", errToString(err), fname);
1021         char* fnameCopy = strdup(fname);
1022         errSet.emplace_back(err, basename(fnameCopy));
1023         free(fnameCopy);
1024         return err;
1025     }
1026     // for adjustMap - update weight
1027     if (adjustMap.find(font.familyName) != nullptr) {
1028         const std::vector<AdjustInfo> adjustSet = *(adjustMap.find(font.familyName));
1029         for (unsigned int i = 0; i < adjustSet.size(); i++) {
1030             if (font.style.weight() == adjustSet[i].origValue) {
1031                 font.style = SkFontStyle(adjustSet[i].newValue, font.style.width(), font.style.slant());
1032                 break;
1033             }
1034         }
1035     }
1036     bool ret = false;
1037     if (count > 1) {
1038         ret = insertTtcFont(count, font);
1039     } else if (axisDefs.count() > 0) {
1040         ret = insertVariableFont(axisDefs, font);
1041     }
1042     if (!ret) {
1043         SkString specifiedName;
1044         TypefaceSet* tpSet = getTypefaceSet(font.familyName, specifiedName);
1045         if (tpSet) {
1046             sk_sp<SkTypeface_OHOS> typeface = sk_make_sp<SkTypeface_OHOS>(specifiedName, font);
1047             tpSet->push_back(std::move(typeface));
1048         }
1049     }
1050     return NO_ERROR;
1051 }
1052 
1053 /*! To scan the system font directories
1054  * \param fontScanner the scanner used to parse a font file
1055  * \return NO_ERROR success
1056  * \return ERROR_DIR_NOT_FOUND a font directory is not exist
1057  */
scanFonts(const SkTypeface_FreeType::Scanner & fontScanner)1058 int FontConfig_OHOS::scanFonts(const SkTypeface_FreeType::Scanner& fontScanner)
1059 {
1060     int err = NO_ERROR;
1061     if (fontDirSet.size() == 0) {
1062 #if defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_WIN) or defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_MAC) or \
1063     defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_LINUX)
1064         fontDirSet.emplace_back(SkString("fonts"));
1065 #else
1066         fontDirSet.emplace_back(SkString("/system/fonts/"));
1067 #endif
1068     }
1069     for (unsigned int i = 0; i < fontDirSet.size(); i++) {
1070         DIR* dir = opendir(fontDirSet[i].c_str());
1071         if (dir == nullptr) {
1072             err = logErrInfo(ERROR_DIR_NOT_FOUND, fontDirSet[i].c_str());
1073             continue;
1074         }
1075         struct dirent* node = nullptr;
1076 #if defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_WIN)
1077         struct stat filestat;
1078 #endif
1079         while ((node = readdir(dir))) {
1080 #if defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_WIN)
1081             stat(node->d_name, &filestat);
1082             if(S_ISDIR(filestat.st_mode)) {
1083                 continue;
1084             }
1085 #else
1086             if (node->d_type != DT_REG) {
1087                 continue;
1088             }
1089 #endif
1090             const char* fname = node->d_name;
1091 
1092             if (G_IS_HMSYMBOL_ENABLE && (strcmp(fname, "hm_symbol_config_next.json") == 0)) {
1093                 HmSymbolConfig_OHOS::GetInstance()->ParseConfigOfHmSymbol(fname, fontDirSet[i]);
1094                 continue;
1095             }
1096 
1097             int len = strlen(fname);
1098             int suffixLen = strlen(".ttf");
1099             if (len < suffixLen || (strncmp(fname + len - suffixLen, ".ttf", suffixLen) &&
1100                 strncmp(fname + len - suffixLen, ".otf", suffixLen) &&
1101                 strncmp(fname + len - suffixLen, ".ttc", suffixLen) &&
1102                 strncmp(fname + len - suffixLen, ".otc", suffixLen))) {
1103                 continue;
1104             }
1105             len += (fontDirSet[i].size() + 2); // 2 more characters for '/' and '\0'
1106             char fullname[len];
1107             memset_s(fullname, len,  0, len);
1108             strcpy_s(fullname, len, fontDirSet[i].c_str());
1109 #if defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_WIN)
1110             if (fontDirSet[i][fontDirSet[i].size() - 1] != '\\') {
1111                 strcat_s(fullname, len, "\\");
1112             }
1113 #else
1114             if (fontDirSet[i][fontDirSet[i].size() - 1] != '/') {
1115                 strcat_s(fullname, len, "/");
1116             }
1117 #endif
1118             strcat_s(fullname, len, fname);
1119             loadFont(fontScanner, fullname);
1120         }
1121         closedir(dir);
1122     }
1123     fontDirSet.clear();
1124     return err;
1125 }
1126 
1127 /*! To reset the generic family
1128  * \n 1. To sort the typefaces for each font style set in generic list
1129  * \n 2. To build typeface set for those font style sets which have single weight value
1130  */
resetGenericValue()1131 void FontConfig_OHOS::resetGenericValue()
1132 {
1133     aliasMap.foreach([this](SkString& key, std::vector<AliasInfo>* pAliasSet) {
1134         std::vector<AliasInfo>& aliasSet = *pAliasSet;
1135         int index = aliasSet[0].pos;
1136         if (genericFamilySet[index]->typefaceSet->size() == 0) {
1137             this->logErrInfo(ERROR_FAMILY_NOT_FOUND, key.c_str());
1138         } else {
1139             sortTypefaceSet(genericFamilySet[index]->typefaceSet);
1140             for (unsigned int i = 1; i < aliasSet.size(); i++) {
1141                 if (aliasSet[i].weight == 0) {
1142                     continue;
1143                 }
1144                 buildSubTypefaceSet(genericFamilySet[index]->typefaceSet,
1145                     genericFamilySet[index + i]->typefaceSet,
1146                     genericFamilySet[index + i]->familyName,
1147                     aliasSet[i].weight);
1148                 if (genericFamilySet[index + i]->typefaceSet->size() == 0) {
1149                     this->logErrInfo(ERROR_FAMILY_NOT_FOUND,
1150                         genericFamilySet[index + i]->familyName.c_str());
1151                 }
1152             }
1153         }
1154     });
1155 
1156     aliasMap.reset();
1157     adjustMap.reset();
1158     variationMap.reset();
1159     ttcIndexMap.reset();
1160 }
1161 
1162 /*! To build a sub typeface set according to weight from a typeface set
1163  * \param typefaceSet the parent typeface set
1164  * \param[out] subSet the sub typeface set returned to the caller
1165  * \param familyName the family name of the sub typeface set
1166  * \param weight the weight of the sub typeface set
1167  */
buildSubTypefaceSet(const std::shared_ptr<TypefaceSet> & typefaceSet,std::shared_ptr<TypefaceSet> & subSet,const SkString & familyName,int weight)1168 void FontConfig_OHOS::buildSubTypefaceSet(const std::shared_ptr<TypefaceSet>& typefaceSet,
1169     std::shared_ptr<TypefaceSet>& subSet, const SkString& familyName, int weight)
1170 {
1171     if (typefaceSet->size() == 0) {
1172         return;
1173     }
1174     for (unsigned int i = 0; i < typefaceSet->size(); i++) {
1175         const SkTypeface_OHOS* typeface = (*typefaceSet)[i].get();
1176         if (typeface && typeface->fontStyle().weight() == weight) {
1177             const FontInfo* pFont = typeface->getFontInfo();
1178             if (pFont == nullptr) {
1179                 continue;
1180             }
1181             FontInfo font(*pFont);
1182             sk_sp<SkTypeface_OHOS> newTypeface = sk_make_sp<SkTypeface_OHOS>(familyName, font);
1183             subSet->push_back(std::move(newTypeface));
1184         }
1185     }
1186 }
1187 
1188 /*! To reset the fallback value
1189  * \n To sort the typefaces for each font style set in fallback list.
1190  */
resetFallbackValue()1191 void FontConfig_OHOS::resetFallbackValue()
1192 {
1193     for (unsigned int i = 0; i < fallbackSet.size(); i++) {
1194         if (fallbackSet[i]->typefaceSet->size() == 0) {
1195             logErrInfo(ERROR_FAMILY_NOT_FOUND, fallbackSet[i]->familyName.c_str());
1196         }
1197         sortTypefaceSet(fallbackSet[i]->typefaceSet);
1198     }
1199 }
1200 
1201 /*! To check if an error happened
1202  * \param err the id of an error
1203  * \param text the key to indicate the part with the error happened
1204  * \return false, this kind of error did not happen
1205  * \return true, the error happened
1206  */
hasError(int err,const SkString & text) const1207 bool FontConfig_OHOS::hasError(int err, const SkString& text) const
1208 {
1209     for (unsigned int i = 0; i < errSet.size(); i++) {
1210         if (errSet[i].err == err && errSet[i].text == text) {
1211             return true;
1212         }
1213     }
1214     return false;
1215 }
1216 
1217 /*! To get the total count of errors happened
1218  * \return The count of errors
1219  */
getErrorCount() const1220 int FontConfig_OHOS::getErrorCount() const
1221 {
1222     return errSet.size();
1223 }
1224 
1225 /*! To sort the typeface set
1226  * \param typefaceSet the typeface set to be sorted
1227  */
sortTypefaceSet(std::shared_ptr<TypefaceSet> & typefaceSet)1228 void FontConfig_OHOS::sortTypefaceSet(std::shared_ptr<TypefaceSet>& typefaceSet)
1229 {
1230     if (typefaceSet.get() == nullptr || typefaceSet->size() <= 1) {
1231         return;
1232     }
1233     TypefaceSet& tpSet = *(typefaceSet.get());
1234     for (unsigned int i = 0; i < tpSet.size(); i++)
1235     for (unsigned int j = 0; j < tpSet.size() - 1; j++) {
1236         if ((tpSet[j]->fontStyle().weight() > tpSet[j + 1]->fontStyle().weight()) ||
1237             (tpSet[j]->fontStyle().weight() == tpSet[j + 1]->fontStyle().weight() &&
1238             tpSet[j]->fontStyle().slant() > tpSet[j + 1]->fontStyle().slant())) {
1239             tpSet[j].swap(tpSet[j + 1]);
1240         }
1241     }
1242 }
1243 
1244 /*! To get the display text of an error
1245  * \param err the id of an error
1246  * \return The text to explain the error
1247  */
errToString(int err)1248 const char* FontConfig_OHOS::errToString(int err)
1249 {
1250     const static std::array<const char*, ERROR_TYPE_COUNT> errToString{
1251         "successful",                                                      // NO_ERROR = 0
1252         "config file is not found",                              // ERROR_CONFIG_NOT_FOUND
1253         "the format of config file is not supported", // ERROR_CONFIG_FORMAT_NOT_SUPPORTED
1254         "missing tag",                                         // ERROR_CONFIG_MISSING_TAG
1255         "invalid value type",                           // ERROR_CONFIG_INVALID_VALUE_TYPE
1256         "font file is not exist",                                  // ERROR_FONT_NOT_EXIST
1257         "invalid font stream",                                // ERROR_FONT_INVALID_STREAM
1258         "no font stream",                                          // ERROR_FONT_NO_STREAM
1259         "family is not found",                                   // ERROR_FAMILY_NOT_FOUND
1260         "no available family in the system",                   //ERROR_NO_AVAILABLE_FAMILY
1261         "no such directory"                                         // ERROR_DIR_NOT_FOUND
1262     };
1263     if (err >= 0 && err < ERROR_TYPE_COUNT) {
1264         return errToString[err];
1265     }
1266     return "unknown error";
1267 }
1268 
1269 /*! To log the error information
1270  * \param err the id of an error
1271  * \param key the key which indicates the the part with the error
1272  * \param expected the expected type of json node.
1273  * \n     It's used only for err 'ERROR_CONFIG_INVALID_VALUE_TYPE'
1274  * \param actual the actual type of json node.
1275  * \n     It's used only for err 'ERROR_CONFIG_INVALID_VALUE_TYPE'
1276  * \return err
1277  */
logErrInfo(int err,const char * key,Json::ValueType expected,Json::ValueType actual)1278 int FontConfig_OHOS::logErrInfo(int err, const char* key, Json::ValueType expected,
1279     Json::ValueType actual)
1280 {
1281     errSet.emplace_back(err, key);
1282     if (err != ERROR_CONFIG_INVALID_VALUE_TYPE) {
1283         LOGE("%s : %s\n", errToString(err), key);
1284     } else {
1285         const char* types[] = {
1286             "null",
1287             "int",
1288             "unit",
1289             "real",
1290             "string",
1291             "boolean",
1292             "array",
1293             "object",
1294         };
1295         int size = sizeof(types) / sizeof(char*);
1296         if ((expected >= 0 && expected < size) &&
1297             (actual >= 0 && actual < size)) {
1298             LOGE("%s : '%s' should be '%s', but here it's '%s'\n",
1299                 errToString(err), key, types[expected], types[actual]);
1300         } else {
1301             LOGE("%s : %s\n", errToString(err), key);
1302         }
1303     }
1304     return err;
1305 }
1306 
judgeFileExist()1307 bool FontConfig_OHOS::judgeFileExist()
1308 {
1309     bool haveFile = false;
1310     for (unsigned int i = 0; i < fontDirSet.size(); i++) {
1311         DIR* dir = opendir(fontDirSet[i].c_str());
1312         if (dir == nullptr) {
1313             logErrInfo(ERROR_DIR_NOT_FOUND, fontDirSet[i].c_str());
1314             continue;
1315         }
1316         struct dirent* node = nullptr;
1317 #if defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_WIN)
1318         struct stat fileStat;
1319 #endif
1320         while ((node = readdir(dir))) {
1321 #if defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_WIN)
1322             stat(node->d_name, &fileStat);
1323             if (S_ISDIR(fileStat.st_mode)) {
1324                 continue;
1325             }
1326 #else
1327             if (node->d_type != DT_REG) {
1328                 continue;
1329             }
1330 #endif
1331             const char* fileName = node->d_name;
1332             int len = strlen(fileName);
1333             int suffixLen = strlen(".ttf");
1334             if (len < suffixLen || (strncmp(fileName + len - suffixLen, ".ttf", suffixLen) &&
1335                 strncmp(fileName + len - suffixLen, ".otf", suffixLen) &&
1336                 strncmp(fileName + len - suffixLen, ".ttc", suffixLen) &&
1337                 strncmp(fileName + len - suffixLen, ".otc", suffixLen))) {
1338                 continue;
1339             }
1340             haveFile = true;
1341             break;
1342         }
1343         (void)closedir(dir);
1344         if (haveFile) {
1345             break;
1346         }
1347     }
1348     return haveFile;
1349 }
1350 
checkProductFile(const char * fname)1351 int FontConfig_OHOS::checkProductFile(const char* fname)
1352 {
1353     std::lock_guard<std::mutex> lock(fontMutex);
1354     int err = parseConfig(PRODUCT_DEFAULT_CONFIG);
1355     SkDebugf("parse productfontconfig json file err = %d", err);
1356     if ((err != NO_ERROR) || (!judgeFileExist())) {
1357         SkDebugf("parse productfontconfig json file error");
1358         fontDirSet.clear();
1359         fallbackForMap.reset();
1360         genericFamilySet.clear();
1361         fallbackSet.clear();
1362         genericNames.reset();
1363         fallbackNames.reset();
1364         errSet.clear();
1365         aliasMap.reset();
1366         adjustMap.reset();
1367         variationMap.reset();
1368         ttcIndexMap.reset();
1369         err = parseConfig(fname);
1370     }
1371     return err;
1372 }