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