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