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