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