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