• 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     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     if (dstWidth <= normalWidth) {
297         if (srcWidth <= dstWidth) {
298             widthDiff = dstWidth - srcWidth;
299         } else {
300             widthDiff = srcWidth - dstWidth + 5;
301         }
302     } else {
303         if (srcWidth >= dstWidth) {
304             widthDiff = srcWidth - dstWidth;
305         } else {
306             widthDiff = dstWidth - srcWidth + 5;
307         }
308     }
309 
310     int diffSlantValue[3][3] = {
311         {0, 2, 1},
312         {2, 0, 1},
313         {2, 1, 0}
314     };
315     uint32_t slantDiff = diffSlantValue[dstStyle.slant()][srcStyle.slant()];
316 
317     int dstWeight = dstStyle.weight();
318     int srcWeight = srcStyle.weight();
319     uint32_t weightDiff = 0;
320 
321     // The maximum weight is kExtraBlack_Weight (1000), when dstWeight and srcWeight are at the different
322     // side of kNormal_Weight, the weight difference between them should be more than 500 (1000/2)
323     if ((dstWeight == SkFontStyle::kNormal_Weight && srcWeight == SkFontStyle::kMedium_Weight) ||
324         (dstWeight == SkFontStyle::kMedium_Weight && srcWeight == SkFontStyle::kNormal_Weight)) {
325         weightDiff = 50;
326     } else if (dstWeight <= SkFontStyle::kNormal_Weight) {
327         if (srcWeight <= dstWeight) {
328             weightDiff = dstWeight - srcWeight;
329         } else {
330             weightDiff = srcWeight - dstWeight + 500;
331         }
332     } else if (dstWeight > SkFontStyle::kNormal_Weight) {
333         if (srcWeight >= dstWeight) {
334             weightDiff = srcWeight - dstWeight;
335         } else {
336             weightDiff = dstWeight - srcWeight + 500;
337         }
338     }
339     // The first 2 bytes to save weight difference, the third byte to save slant difference,
340     // and the fourth byte to save width difference
341     uint32_t diff = (widthDiff << 24) + (slantDiff << 16) + weightDiff;
342     return diff;
343 }
344 
345 /*! To get the data of font configuration file
346  * \param fname the full name of the font configuration file
347  * \param[out] size the size of data returned to the caller
348  * \return The pointer of content of the file
349  * \note The returned pointer should be freed by the caller
350  */
getFileData(const char * fname,int & size)351 char* FontConfig_OHOS::getFileData(const char* fname, int& size)
352 {
353     FILE* fp = fopen(fname, "r");
354     if (fp == nullptr) {
355         return nullptr;
356     }
357     fseek(fp, 0L, SEEK_END);
358     size = ftell(fp) + 1;
359     rewind(fp);
360     void* data = malloc(size);
361     if (data == nullptr) {
362         fclose(fp);
363         return nullptr;
364     }
365     memset_s(data, size, 0, size);
366     (void) fread(data, size, 1, fp);
367     fclose(fp);
368     return (char*)data;
369 }
370 
371 /*! parse the system font configuration document
372  * \param fname the full name of the font configuration document
373  * \return NO_ERROR successful
374  * \return ERROR_CONFIG_NOT_FOUND config document is not found
375  * \return ERROR_CONFIG_FORMAT_NOT_SUPPORTED config document format is not supported
376  * \return ERROR_CONFIG_INVALID_VALUE_TYPE wrong type of value in the configuration
377  */
parseConfig(const char * fname)378 int FontConfig_OHOS::parseConfig(const char* fname)
379 {
380     if (fname == nullptr) {
381         fname = OHOS_DEFAULT_CONFIG;
382     }
383     Json::Value root;
384     int err = checkConfigFile(fname, root);
385     if (err != NO_ERROR) {
386         return err;
387     }
388     // "fontdir" - optional, the data type should be string
389     const char* key = "fontdir";
390     if (root.isMember(key)) {
391         if (root[key].isArray()) {
392             parseFontDir(fname, root[key]);
393         } else {
394             return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key);
395         }
396     }
397     // "generic", "fallback" - necessary, the data type should be array
398     const char* keys[] = {"generic", "fallback", nullptr};
399     int index = 0;
400     while (true) {
401         if (keys[index] == nullptr) {
402             break;
403         }
404         key = keys[index++];
405         if (!root.isMember(key)) {
406             return logErrInfo(ERROR_CONFIG_MISSING_TAG, key);
407         } else if (!root[key].isArray()) {
408             return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key, Json::arrayValue, root[key].type());
409         }
410         const Json::Value& arr = root[key];
411         for (unsigned int i = 0; i < arr.size(); i++) {
412             if (arr[i].isObject()) {
413                 if (!strcmp(key, "generic")) {
414                     parseGeneric(arr[i]);
415                 } else if (!strcmp(key, "fallback")) {
416                     parseFallback(arr[i]);
417                 }
418             } else {
419                 SkString errKey;
420                 errKey.appendf("%s#%d", key, i + 1);
421                 (void) logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, errKey.c_str(),
422                     Json::objectValue, arr[i].type());
423             }
424         }
425     }
426     root.clear();
427     return NO_ERROR;
428 }
429 
430 /*! check the system font configuration document
431  * \param fname the full name of the font configuration document
432  * \return NO_ERROR successful
433  * \return ERROR_CONFIG_NOT_FOUND config document is not found
434  * \return ERROR_CONFIG_FORMAT_NOT_SUPPORTED config document format is not supported
435  */
checkConfigFile(const char * fname,Json::Value & root)436 int FontConfig_OHOS::checkConfigFile(const char* fname, Json::Value& root)
437 {
438     int size = 0;
439     char* data = getFileData(fname, size);
440     if (data == nullptr) {
441         return logErrInfo(ERROR_CONFIG_NOT_FOUND, fname);
442     }
443     JSONCPP_STRING errs;
444     Json::CharReaderBuilder charReaderBuilder;
445     std::unique_ptr<Json::CharReader> jsonReader(charReaderBuilder.newCharReader());
446     bool isJson = jsonReader->parse(data, data + size, &root, &errs);
447     free((void*)data);
448     data = nullptr;
449 
450     if (!isJson || !errs.empty()) {
451         return logErrInfo(ERROR_CONFIG_FORMAT_NOT_SUPPORTED, fname);
452     }
453     return NO_ERROR;
454 }
455 #if ENABLE_DEBUG
456 /*! To print out the font information
457  * \param font the font object to be printed
458  */
dumpFont(const FontInfo & font) const459 void FontConfig_OHOS::dumpFont(const FontInfo& font) const
460 {
461     LOGI("name=%s, family=%s, weight=%d, width=%d, slant=%d, index=%d",
462         font.fname.c_str(), font.familyName.c_str(), font.style.weight(), font.style.width(), font.style.slant(),
463         font.index);
464     int count = font.axisSet.axis.size();
465     if (count > 0) {
466         SkString str;
467         for (unsigned int i = 0; i < count; i++) {
468             str.appendU32(SkFixedFloorToInt(font.axisSet.axis[i]));
469             if (i < count - 1) {
470                 str.append(",");
471             }
472         }
473         LOGI("axis={%s}\n", str.c_str());
474     }
475 }
476 
477 /*! To print out the information of generic font style set
478  */
dumpGeneric() const479 void FontConfig_OHOS::dumpGeneric() const
480 {
481     LOGI("\n");
482     for (unsigned int i = 0; i < genericFamilySet.size(); i++) {
483         LOGI("[%d] familyName : %s - %d\n", i, genericFamilySet[i]->familyName.c_str(),
484             static_cast<int>(genericFamilySet[i]->typefaceSet->size()));
485         for (int j = 0; j < genericFamilySet[i]->typefaceSet->size(); j++) {
486             if ((*(genericFamilySet[i]->typefaceSet))[j].get()) {
487                 const FontInfo* font = (*(genericFamilySet[i]->typefaceSet))[j]->getFontInfo();
488                 if (font) {
489                     dumpFont(*font);
490                 } else {
491                     LOGE("font [%d] is null\n", j);
492                 }
493             } else {
494                 LOGE("typefeace [%d] is null\n", j);
495             }
496         }
497     }
498 }
499 
500 /*! To print out the information of fallback font style set
501  */
dumpFallback() const502 void FontConfig_OHOS::dumpFallback() const
503 {
504     LOGI("\n");
505     int count = 0;
506     fallbackForMap.foreach([this, &count](const SkString& key,
507         const FallbackSetPos& setIndex) {
508         LOGI("[%d] family : %s - %d\n", count++, key.c_str(), setIndex.count);
509         for (unsigned int i = setIndex.index; i < setIndex.index + setIndex.count; i++) {
510             const TypefaceSet& tpSet = *(fallbackSet[i]->typefaceSet.get());
511             LOGI("[%s] - %d\n", fallbackSet[i]->familyName.c_str(), static_cast<int>(tpSet.size()));
512 
513             for (unsigned int j = 0; j < tpSet.size(); j++) {
514                 const FontInfo* font = tpSet[j]->getFontInfo();
515                 if (font) {
516                     this->dumpFont(*font);
517                 } else {
518                     LOGE("font [%d] is null\n", j);
519                 }
520             }
521         }
522     });
523 }
524 #endif
525 
526 /*! To parse 'fontdir' attribute
527  * \param root the root node of 'fontdir'
528  * \return NO_ERROR successful
529  * \return ERROR_CONFIG_INVALID_VALUE_TYPE invalid value type
530  */
parseFontDir(const char * fname,const Json::Value & root)531 int FontConfig_OHOS::parseFontDir(const char* fname, const Json::Value& root)
532 {
533     for (unsigned int i = 0; i < root.size(); i++) {
534         if (root[i].isString()) {
535             const char* dir;
536 #if defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_WIN) or defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_MAC) or \
537     defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_LINUX)
538             if (strcmp(fname, OHOS_DEFAULT_CONFIG) == 0) {
539                 dir = strcmp(root[i].asCString(), "/system/fonts/") ? root[i].asCString() : "fonts";
540             } else {
541                 dir = strcmp(root[i].asCString(), "/system/fonts/") ?
542                     root[i].asCString() : "../../../../hms/previewer/resources/fonts";
543             }
544 #else
545             dir = root[i].asCString();
546 #endif
547             fontDirSet.emplace_back(SkString(dir));
548         } else {
549             SkString text;
550             text.appendf("fontdir#%d", i + 1);
551             return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, text.c_str(), Json::stringValue, root[i].type());
552         }
553     }
554     return NO_ERROR;
555 }
556 
557 /*! To parse an item of 'generic' family
558  * \param root the root node of an item in 'generic' list
559  * \return NO_ERROR successful
560  * \return ERROR_CONFIG_INVALID_VALUE_TYPE invalid value type for an attribute
561  * \return ERROR_CONFIG_MISSING_TAG missing tag of 'family' or 'alias'
562  */
parseGeneric(const Json::Value & root)563 int FontConfig_OHOS::parseGeneric(const Json::Value& root)
564 {
565     // "family" - necessary, the data type should be String
566     const char* key = "family";
567     if (!root.isMember(key)) {
568         return logErrInfo(ERROR_CONFIG_MISSING_TAG, key);
569     } else if (!root[key].isString()) {
570         return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key, Json::stringValue, root[key].type());
571     }
572     SkString familyName = SkString(root[key].asCString());
573     // "alias" - necessary, the data type should be Array
574     if (!root.isMember("alias")) {
575         return logErrInfo(ERROR_CONFIG_MISSING_TAG, "alias");
576     }
577     // "adjust", "variation" - optional
578     const char* tags[] = {"alias", "adjust", "variations", "index"};
579     std::vector<AliasInfo> aliasSet;
580     std::vector<AdjustInfo> adjustSet;
581     std::vector<VariationInfo> variationSet;
582     for (unsigned int i = 0; i < sizeof(tags) / sizeof(char*); i++) {
583         key = tags[i];
584         if (!root.isMember(key)) {
585             continue;
586         }
587         if (root[key].isArray()) {
588             if (!strcmp(key, "index")) {
589                 parseTtcIndex(root[key], familyName);
590                 continue;
591             }
592             const Json::Value& arr = root[key];
593             for (unsigned int j = 0; j < arr.size(); j++) {
594                 if (arr[j].isObject()) {
595                     if (!strcmp(key, "alias")) {
596                         parseAlias(arr[j], aliasSet);
597                     } else if (!strcmp(key, "adjust")) {
598                         parseAdjust(arr[j], adjustSet);
599                     } else {
600                         parseVariation(arr[j], variationSet);
601                     }
602                 } else {
603                     SkString text;
604                     text.appendf("%s#%d", key, j + 1);
605                     (void) logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, text.c_str(), Json::objectValue,
606                         arr[j].type());
607                 }
608             }
609         } else {
610             (void) logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key, Json::arrayValue, root[key].type());
611         }
612         if (root.size() == 2) {
613             break;
614         }
615     }
616     if (aliasSet.size()) {
617         aliasMap.set(SkString(familyName), aliasSet);
618     }
619     if (adjustSet.size()) {
620         adjustMap.set(SkString(familyName), adjustSet);
621     }
622     if (variationSet.size()) {
623         variationMap.set(SkString(familyName), variationSet);
624     }
625     return NO_ERROR;
626 }
627 
628 /*! To parse an item of 'alias' attribute
629  * \param root the root node of an item in an 'alias' list
630  * \param[out] aliasSet the value of AliasInfo will be written to and returned to the caller
631  * \return NO_ERROR successful
632  * \return ERROR_CONFIG_INVALID_VALUE_TYPE invalid value type for an attribute
633  * \return ERROR_CONFIG_MISSING_TAG missing tag of alias name
634  */
parseAlias(const Json::Value & root,std::vector<AliasInfo> & aliasSet)635 int FontConfig_OHOS::parseAlias(const Json::Value& root, std::vector<AliasInfo>& aliasSet)
636 {
637     if (root.empty()) {
638         return logErrInfo(ERROR_CONFIG_MISSING_TAG, "generic-alias-name");
639     }
640     Json::Value::Members members = root.getMemberNames();
641     const char* key = members[0].c_str();
642     if (!root[key].isInt()) {
643         return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, "generic-alias-weight",
644             Json::intValue, root[key].type());
645     }
646 
647     SkString aliasName = SkString(key);
648     int weight = root[key].asInt();
649     std::unique_ptr<GenericFamily> genericFamily = std::make_unique<GenericFamily>();
650     genericFamily->familyName = SkString(key);
651     if (aliasSet.size() == 0 || weight > 0) {
652         genericFamily->typefaceSet = std::make_shared<TypefaceSet>();
653     } else {
654         int index = aliasSet[0].pos;
655         genericFamily->typefaceSet = genericFamilySet[index]->typefaceSet;
656     }
657     genericNames.set(SkString(genericFamily->familyName), genericFamilySet.size());
658 
659     AliasInfo info = {static_cast<int>(genericFamilySet.size()), weight};
660     aliasSet.emplace_back(std::move(info));
661     genericFamilySet.emplace_back(std::move(genericFamily));
662     return NO_ERROR;
663 }
664 
665 /*! To parse an item of 'adjust' attribute
666  * \param root the root node of an item in an 'adjust' list
667  * \param[out] adjustSet the value of AdjustInfo will be written to and returned to the caller
668  * \return NO_ERROR successful
669  * \return ERROR_CONFIG_INVALID_VALUE_TYPE invalid value type for an attribute
670  * \return ERROR_CONFIG_MISSING_TAG missing tag of 'weight' or 'to'
671  */
parseAdjust(const Json::Value & root,std::vector<AdjustInfo> & adjustSet)672 int FontConfig_OHOS::parseAdjust(const Json::Value& root, std::vector<AdjustInfo>& adjustSet)
673 {
674     const char* tags[] = {"weight", "to"};
675     int values[2]; // value[0] - to save 'weight', value[1] - to save 'to'
676     for (unsigned int i = 0; i < sizeof(tags) / sizeof(char*); i++) {
677         const char* key = tags[i];
678         if (!root.isMember(key)) {
679             return logErrInfo(ERROR_CONFIG_MISSING_TAG, key);
680         } else if (!root[key].isInt()) {
681             return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key,
682                 Json::intValue, root[key].type());
683         } else {
684             values[i] = root[key].asInt();
685         }
686     }
687     AdjustInfo info = {values[0], values[1]};
688     adjustSet.push_back(info);
689     return NO_ERROR;
690 }
691 
692 /*! To parse an item of 'fallback' attribute
693  * \param root the root node of an item in 'fallback' list
694  * \return NO_ERROR successful
695  * \return ERROR_CONFIG_INVALID_VALUE_TYPE invalid value type for an attribute
696  * \return ERROR_CONFIG_MISSING_TAG missing tag of fallbackFor
697  */
parseFallback(const Json::Value & root)698 int FontConfig_OHOS::parseFallback(const Json::Value& root)
699 {
700     if (root.empty()) {
701         return logErrInfo(ERROR_CONFIG_MISSING_TAG, "fallback-fallbackFor");
702     }
703     Json::Value::Members members = root.getMemberNames();
704     const char* key = members[0].c_str();
705     if (!root[key].isArray()) {
706         return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, "fallback-items",
707             Json::arrayValue, root[key].type());
708     }
709     unsigned int startPos = fallbackSet.size();
710     SkString fallbackFor = SkString(key);
711     const Json::Value& fallbackArr = root[key];
712     for (unsigned int i = 0; i < fallbackArr.size(); i++) {
713         if (!fallbackArr[i].isObject()) {
714             SkString text;
715             text.appendf("fallback-%s#%d", key, i + 1);
716             (void) logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, text.c_str(), Json::objectValue,
717                 fallbackArr[i].type());
718             continue;
719         }
720         parseFallbackItem(fallbackArr[i]);
721     }
722     FallbackSetPos setPos = {startPos, (unsigned int)(fallbackSet.size() - startPos)};
723     fallbackForMap.set(fallbackFor, setPos);
724     return NO_ERROR;
725 }
726 
727 /*! To parse an item of fallback family
728  * \param root the root node of a fallback item
729  * \return NO_ERROR successful
730  * \return ERROR_CONFIG_INVALID_VALUE_TYPE invalid value type for an attribute
731  * \return ERROR_CONFIG_MISSING_TAG missing tag of language
732  */
parseFallbackItem(const Json::Value & root)733 int FontConfig_OHOS::parseFallbackItem(const Json::Value& root)
734 {
735     if (root.empty()) {
736         return logErrInfo(ERROR_CONFIG_MISSING_TAG, "fallback-item-lang");
737     }
738     Json::Value::Members members = root.getMemberNames();
739     const char* key = nullptr;
740     bool hasIndex = false;
741     bool hasVariations = false;
742     for (unsigned int i = 0; i < members.size(); i++) {
743         if (members[i] == "variations") {
744             hasVariations = true;
745         } else if (members[i] == "index") {
746             hasIndex = true;
747         } else {
748             key = members[i].c_str();
749         }
750     }
751     if (key == nullptr) {
752         return logErrInfo(ERROR_CONFIG_MISSING_TAG, "fallback-item-lang");
753     }
754     if (!root[key].isString()) {
755         return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, "fallback-item-family",
756             Json::stringValue, root[key].type());
757     }
758     SkString lang = SkString(key);
759     SkString familyName = SkString(root[key].asCString());
760     if (hasVariations) {
761         key = "variations";
762         if (root[key].isArray()) {
763             const Json::Value& varArr = root[key];
764             std::vector<VariationInfo> variationSet;
765             for (unsigned int i = 0; i < varArr.size(); i++) {
766                 if (varArr[i].isObject()) {
767                     parseVariation(varArr[i], variationSet);
768                 } else {
769                     SkString text = SkString("variations#");
770                     text.appendU32(i + 1);
771                     (void) logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, text.c_str(),
772                         Json::objectValue, varArr[i].type());
773                 }
774             }
775             if (variationSet.size()) {
776                 variationMap.set(SkString(familyName), variationSet);
777             }
778         } else {
779             (void) logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key, Json::arrayValue,
780                 root[key].type());
781         }
782     }
783     if (hasIndex) {
784         key = "index";
785         if (root[key].isArray()) {
786             parseTtcIndex(root[key], familyName);
787         } else {
788             (void) logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key, Json::arrayValue, root[key].type());
789         }
790     }
791     std::unique_ptr<FallbackInfo> fallback = std::make_unique<FallbackInfo>();
792     fallback->familyName = familyName;
793     fallback->langs = lang;
794     fallback->typefaceSet = std::make_shared<TypefaceSet>();
795     fallbackNames.set(SkString(familyName), fallbackSet.size());
796     fallbackSet.emplace_back(std::move(fallback));
797     return NO_ERROR;
798 }
799 
800 /*! To parse an item of 'variations' attribute
801  * \param root the root node of an item in 'variations' list
802  * \param[out] variationSet the value of VariationInfo is written to and returned to the caller
803  * \return NO_ERROR successful
804  * \return ERROR_CONFIG_INVALID_VALUE_TYPE invalid value type for an attribute
805  * \return ERROR_CONFIG_MISSING_TAG missing tag of 'weight' or 'wght'
806  */
parseVariation(const Json::Value & root,std::vector<VariationInfo> & variationSet)807 int FontConfig_OHOS::parseVariation(const Json::Value& root, std::vector<VariationInfo>& variationSet)
808 {
809     const char* key = nullptr;
810     const char* tags[] = {"wght", "wdth", "slnt", "weight", "width", "slant"};
811     VariationInfo info;
812     for (unsigned int i = 0; i < sizeof(tags) / sizeof(char*); i++) {
813         key = tags[i];
814         if ((!strcmp(key, "wght") || !strcmp(key, "weight")) &&
815             !root.isMember(key)) {
816             return logErrInfo(ERROR_CONFIG_MISSING_TAG, key);
817         }
818         if (!root.isMember(key)) {
819             continue;
820         }
821         if (!strcmp(key, "weight")) {
822             if (!root[key].isInt()) {
823                 return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key, Json::intValue, root[key].type());
824             }
825             info.weight = root[key].asInt();
826         } else if (!strcmp(key, "width")) {
827             if (!root[key].isInt()) {
828                 return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key, Json::intValue, root[key].type());
829             }
830             info.width = root[key].asInt();
831         } else if (!strcmp(key, "slant")) {
832             if (!root[key].isString()) {
833                 return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key, Json::stringValue, root[key].type());
834             }
835             const char* str = root[key].asCString();
836             if (!strcmp(str, "normal")) {
837                 info.slant = static_cast<int>(SkFontStyle::kUpright_Slant);
838             } else if (!strcmp(str, "italic")) {
839                 info.slant = static_cast<int>(SkFontStyle::kItalic_Slant);
840             } else if (!strcmp(str, "oblique")) {
841                 info.slant = static_cast<int>(SkFontStyle::kOblique_Slant);
842             }
843         } else {
844             if (!root[key].isNumeric()) {
845                 return logErrInfo(ERROR_CONFIG_INVALID_VALUE_TYPE, key, Json::realValue, root[key].type());
846             }
847             Coordinate axis;
848             axis.axis = SkSetFourByteTag(key[0], key[1], key[2], key[3]);
849             axis.value = root[key].asFloat();
850             info.axis.emplace_back(axis);
851         }
852     }
853     variationSet.emplace_back(info);
854     return NO_ERROR;
855 }
856 
857 /*! To parse  'index' attribute
858  * \param root the root node of 'index' attribute
859  * \param familyName the name of the family which the root node belongs to
860  * \return NO_ERROR successful
861  * \return ERROR_CONFIG_INVALID_VALUE_TYPE invalid value type for an attribute
862  */
parseTtcIndex(const Json::Value & root,const SkString & familyName)863 int FontConfig_OHOS::parseTtcIndex(const Json::Value& root, const SkString& familyName)
864 {
865     unsigned int keyCount = 2; // the value of 'index' is an array with 2 items.
866     if (root.size() == keyCount && root[0].isString() && root[1].isNumeric()) {
867         TtcIndexInfo item = { SkString(root[0].asCString()), root[1].asInt() };
868         if (item.ttcIndex != 0 && ttcIndexMap.find(item.familyName) == nullptr) {
869             ttcIndexMap.set(SkString(item.familyName), {SkString(item.familyName), 0});
870         }
871         ttcIndexMap.set(SkString(familyName), item);
872     } else {
873         int ret = ERROR_CONFIG_INVALID_VALUE_TYPE;
874         SkString text;
875         const char* key = "index";
876         if (root.size() != keyCount) {
877             text.appendf("%s#0", key);
878             errSet.emplace_back(ret, text.c_str());
879             LOGE("%s : '%s' size should be 2, but here it's %d\n", errToString(ret), key, root.size());
880             return ret;
881         } else if (!root[0].isString()) {
882             text.appendf("%s#1", key);
883             return logErrInfo(ret, text.c_str(), Json::stringValue, root[0].type());
884         } else {
885             text.appendf("%s#2", key);
886             return logErrInfo(ret, text.c_str(), Json::intValue, root[1].type());
887         }
888     }
889     return NO_ERROR;
890 }
891 
892 /*! To get the axis value and set to 'font'
893  * \param axisDefs the axis ranges of a font
894  * \param variation the variation data from which axis values are generated
895  * \param[out] font the axis values will be written to and returned to the caller
896  */
getAxisValues(const AxisDefinitions & axisDefs,const VariationInfo & variation,FontInfo & font) const897 void FontConfig_OHOS::getAxisValues(const AxisDefinitions& axisDefs,
898     const VariationInfo& variation, FontInfo& font) const
899 {
900     SkFontArguments::VariationPosition position;
901     position.coordinateCount = variation.axis.size();
902     position.coordinates = variation.axis.data();
903 
904     int count = axisDefs.count();
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 }