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