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