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