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