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 #ifdef ENABLE_TEXT_ENHANCE
5
6 #include "FontConfig_ohos.h"
7
8 #include <algorithm>
9 #include <array>
10 #include <cstring>
11 #include <dirent.h>
12 #include <fstream>
13 #include <functional>
14 #include <libgen.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <unistd.h>
18
19 #if defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_WIN) or defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_MAC) or \
20 defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_LINUX)
21 #define SK_BUILD_FONT_MGR_FOR_PREVIEW
22 #endif
23
24 #ifdef SK_BUILD_FONT_MGR_FOR_OHOS
25 #include <parameters.h>
26 #endif
27
28 #include "SkFontStyle.h"
29 #include "SkString.h"
30 #include "securec.h"
31
32 using namespace ErrorCode;
33 static const char* PRODUCT_DEFAULT_CONFIG = "/system/etc/productfontconfig.json";
34
35 #ifdef SK_BUILD_FONT_MGR_FOR_OHOS
36 static const bool G_IS_HMSYMBOL_ENABLE =
37 (std::atoi(OHOS::system::GetParameter("persist.sys.graphic.hmsymbolcfg.enable", "1").c_str()) != 0);
38 #else
39 static const bool G_IS_HMSYMBOL_ENABLE = true;
40 #endif
41
42 #ifdef SK_BUILD_FONT_MGR_FOR_PREVIEW
43 static const char* OHOS_DEFAULT_CONFIG = "fontconfig_ohos.json";
44 /*! Constructor
45 * \param fontScanner the scanner to get the font information from a font file
46 * \param fname the full name of system font configuration document.
47 * \n The default value is '/system/etc/fontconfig_ohos.json', if fname is given null
48 */
FontConfig_OHOS(const SkFontScanner_FreeType & fontScanner,const char * fname)49 FontConfig_OHOS::FontConfig_OHOS(const SkFontScanner_FreeType& fontScanner, const char* fname)
50 : fFontScanner(fontScanner)
51 {
52 int err = parseConfig(fname);
53 if (err != NO_ERROR) {
54 return;
55 }
56 loadHMSymbol();
57 }
58 #else
59 static const char* OHOS_DEFAULT_CONFIG = "/system/etc/fontconfig_ohos.json";
60 /*! Constructor
61 * \param fontScanner the scanner to get the font information from a font file
62 * \param fname the full name of system font configuration document.
63 * \n The default value is '/system/etc/fontconfig_ohos.json', if fname is given null
64 */
FontConfig_OHOS(const SkFontScanner_FreeType & fontScanner,const char * fname)65 FontConfig_OHOS::FontConfig_OHOS(const SkFontScanner_FreeType& fontScanner, const char* fname)
66 : fFontScanner(fontScanner)
67 {
68 int err = checkProductFile(fname);
69 if (err != NO_ERROR) {
70 return;
71 }
72 loadHMSymbol();
73 }
74 #endif
75
76 /*! To get the count of font style sets supported in the system
77 * \return The count of font style sets in generic family
78 */
getFamilyCount() const79 int FontConfig_OHOS::getFamilyCount() const
80 {
81 return fFontCollection.fGeneric.size();
82 }
83
84 /*! To match the fallback typeface by the given style and character
85 * this function will traverse all the fallback typefaces
86 * \param character the character to be matched
87 * \param style the style to be matched
88 * \return the matched typeface
89 */
matchFallback(SkUnichar character,const SkFontStyle & style) const90 sk_sp<SkTypeface> FontConfig_OHOS::matchFallback(SkUnichar character, const SkFontStyle& style) const
91 {
92 int16_t index = charRangeIndex(character);
93 if (index < 0) {
94 return nullptr;
95 }
96 for (const auto& i : fFontCollection.fRangeToIndex[index]) {
97 const auto& typefaces = fFontCollection.fFallback[i].typefaces;
98 if (!typefaces.empty() && typefaces[0]->unicharToGlyph(character)) {
99 return matchFontStyle(typefaces, style);
100 }
101 }
102 return nullptr;
103 }
104
105 /*! To match the fallback typeface by the given index style and character
106 * this function only traverse the fallback typefaces in the given index
107 * \param index the index of fallback typefaces
108 * \param character the character to be matched
109 * \param style the style to be matched
110 * \return the matched typeface
111 */
matchFallback(size_t index,SkUnichar character,const SkFontStyle & style) const112 sk_sp<SkTypeface> FontConfig_OHOS::matchFallback(size_t index, SkUnichar character, const SkFontStyle& style) const
113 {
114 if (index >= fFontCollection.fFallback.size()) {
115 return nullptr;
116 }
117 const auto& typefaces = fFontCollection.fFallback[index].typefaces;
118 if (!typefaces.empty() && typefaces[0]->unicharToGlyph(character)) {
119 auto typeface = matchFontStyle(typefaces, style);
120 return typeface;
121 }
122 return nullptr;
123 }
124
125 /*! To match the fallback typeface by the given function
126 * this function will traverse all the fallback typefaces
127 * \param match the judge func, if the func return -1, it means the language tag is not matched
128 * \return the matched fallback typefaces' index set
129 */
matchFallbackByBCP47(std::function<int (const std::string &)> match) const130 std::vector<size_t> FontConfig_OHOS::matchFallbackByBCP47(std::function<int(const std::string&)> match) const
131 {
132 std::vector<size_t> res;
133 for (size_t i = 0; i < fFontCollection.fFallback.size(); i += 1) {
134 if (match(fFontCollection.fFallback[i].lang) != -1) {
135 res.push_back(i);
136 }
137 }
138 return res;
139 }
140
141 /*! To get a typeface by the given family name and style
142 * this function will traverse both the fallback and general typefaces
143 * \param familyName the family name of the fallback typeface
144 * \param style the style of the fallback typeface
145 * \return the matched typeface
146 */
getFallbackTypeface(const SkString & familyName,const SkFontStyle & style) const147 sk_sp<SkTypeface_OHOS> FontConfig_OHOS::getFallbackTypeface(const SkString& familyName, const SkFontStyle& style) const
148 {
149 std::pair<size_t, FontType> res;
150 if (!fFontCollection.getIndexByFamilyName(familyName.c_str(), res)) {
151 return nullptr;
152 }
153
154 const auto& tpSet = fFontCollection.getSet(true)[res.first].typefaces;
155 if (tpSet.size() == 0) {
156 return nullptr;
157 }
158 return FontConfig_OHOS::matchFontStyle(tpSet, style);
159 }
160
161 /*! To get the family name of the default font style set
162 * \param[out] familyName a pointer of SkString object, to which the family value will be set.
163 * \return The count of typeface in this font style set
164 * \n Return -1, if there is no any font style set in the system.
165 */
getDefaultFamily(SkString & familyName) const166 int FontConfig_OHOS::getDefaultFamily(SkString& familyName) const
167 {
168 return getFamilyName(0, familyName);
169 }
170
171 /*! To get the family name of a font style set
172 * \param index the index of a font style set in generic family
173 * \param[out] familyName a pointer of SkString object, to which the family value will be set
174 * \return The count of typeface in the font style set
175 * \n Return -1, if the 'index' is out of range
176 */
getFamilyName(size_t index,SkString & familyName) const177 int FontConfig_OHOS::getFamilyName(size_t index, SkString& familyName) const
178 {
179 if (index >= getFamilyCount()) {
180 familyName = "";
181 return -1;
182 }
183 familyName = fFontCollection.fGeneric[index].alias.c_str();
184 return fFontCollection.fGeneric[index].typefaces.size();
185 }
186
187 /*! To get the count of a font style set
188 * \param styleIndex the index of a font style set
189 * \param isFallback to indicate the font style set is from generic family or fallback family
190 * \n false , the font style set is from generic family list
191 * \n true, the font style set is from fallback family list
192 * \return The count of typeface in the font style set
193 */
getTypefaceCount(size_t styleIndex,bool isFallback) const194 size_t FontConfig_OHOS::getTypefaceCount(size_t styleIndex, bool isFallback) const
195 {
196 auto& set = fFontCollection.getSet(isFallback);
197 return (styleIndex < set.size()) ? set[styleIndex].typefaces.size() : 0;
198 }
199
200 /*! To get a typeface
201 * \param styleIndex the index of a font style set
202 * \param index the index of a typeface in its style set
203 * \param isFallback false, the font style set is generic
204 * \n true, the font style set is fallback
205 * \return The pointer of a typeface
206 * \n Return null, if 'styleIndex' or 'index' is out of range
207 */
getTypeface(size_t styleIndex,size_t index,bool isFallback) const208 sk_sp<SkTypeface_OHOS> FontConfig_OHOS::getTypeface(size_t styleIndex, size_t index, bool isFallback) const
209 {
210 sk_sp<SkTypeface_OHOS> typeface = getTypefaceSP(styleIndex, index, isFallback);
211 return (typeface == nullptr) ? nullptr : typeface;
212 }
213
getTypefaceSP(size_t styleIndex,size_t index,bool isFallback) const214 sk_sp<SkTypeface_OHOS> FontConfig_OHOS::getTypefaceSP(size_t styleIndex, size_t index, bool isFallback) const
215 {
216 auto& fontSet = fFontCollection.getSet(isFallback);
217 if (styleIndex <= fontSet.size()) {
218 // if index less than typefaces' size, return the ptr
219 return (index < fontSet[styleIndex].typefaces.size()) ? fontSet[styleIndex].typefaces[index] : nullptr;
220 }
221 return nullptr;
222 }
223
224 /*! To get a typeface
225 * \param styleIndex the index a font style set
226 * \param style the font style to be matching
227 * \param isFallback false, the font style set is generic
228 * \n true, the font style set is fallback
229 * \return An object of typeface whose font style is the closest matching to 'style'
230 * \n Return null, if 'styleIndex' is out of range
231 */
getTypeface(size_t styleIndex,const SkFontStyle & style,bool isFallback) const232 sk_sp<SkTypeface_OHOS> FontConfig_OHOS::getTypeface(size_t styleIndex, const SkFontStyle& style, bool isFallback) const
233 {
234 auto& fontSet = fFontCollection.getSet(isFallback);
235 if (styleIndex >= fontSet.size()) {
236 return nullptr;
237 }
238
239 const std::vector<sk_sp<SkTypeface_OHOS>>& pSet = fontSet[styleIndex].typefaces;
240 sk_sp<SkTypeface_OHOS> tp = matchFontStyle(pSet, style);
241 return tp;
242 }
243
244 /*! To get the index of a font style set
245 * \param familyName the family name of the font style set
246 * \n get the index of default font style set, if 'familyName' is null
247 * \param[out] isFallback to tell if the family is from generic or fallback to the caller.
248 * \n isFallback is false, if the font style is from generic family list
249 * \n isFallback is true, if the font style is from fallback family list
250 * \param[out] index the index of the font set
251 * \return The index of the font style set
252 * \n Return false, if 'familyName' is not found in the system
253 */
getStyleIndex(const char * familyName,bool & isFallback,size_t & index) const254 bool FontConfig_OHOS::getStyleIndex(const char* familyName, bool& isFallback, size_t& index) const
255 {
256 if (familyName == nullptr) {
257 isFallback = false;
258 return true;
259 }
260
261 std::lock_guard<std::mutex> lock(fFontMutex);
262 std::pair<size_t, FontType> res;
263 if (fFontCollection.getIndexByFamilyName(familyName, res)) {
264 isFallback = res.second == FontType::Fallback;
265 index = res.first;
266 return true;
267 }
268 return false;
269 }
270
271 /*! Find the closest matching typeface
272 * \param typefaceSet a typeface set belonging to the same font style set
273 * \param pattern the font style to be matching
274 * \return The typeface object which is the closest matching to 'pattern'
275 * \n Return null, if the count of typeface is 0
276 */
matchFontStyle(const std::vector<sk_sp<SkTypeface_OHOS>> & typefaceSet,const SkFontStyle & pattern)277 sk_sp<SkTypeface_OHOS> FontConfig_OHOS::matchFontStyle(
278 const std::vector<sk_sp<SkTypeface_OHOS>>& typefaceSet, const SkFontStyle& pattern)
279 {
280 int count = typefaceSet.size();
281 if (count == 1) {
282 return typefaceSet[0];
283 }
284 sk_sp<SkTypeface_OHOS> res = nullptr;
285 uint32_t minDiff = 0xFFFFFFFF;
286 for (int i = 0; i < count; i++) {
287 const SkFontStyle& fontStyle = typefaceSet[i]->fontStyle();
288 uint32_t diff = getFontStyleDifference(pattern, fontStyle);
289 if (diff < minDiff) {
290 minDiff = diff;
291 res = typefaceSet[i];
292 }
293 }
294 return res;
295 }
296
297 /*! To get the difference between a font style and the matching font style
298 * \param dstStyle the style to be matching
299 * \param srcStyle a font style
300 * \return The difference value of a specified style with the matching style
301 */
getFontStyleDifference(const SkFontStyle & dstStyle,const SkFontStyle & srcStyle)302 uint32_t FontConfig_OHOS::getFontStyleDifference(const SkFontStyle& dstStyle,
303 const SkFontStyle& srcStyle)
304 {
305 int normalWidth = SkFontStyle::kNormal_Width;
306 int dstWidth = dstStyle.width();
307 int srcWidth = srcStyle.width();
308
309 uint32_t widthDiff = 0;
310 // The maximum font width is kUltraExpanded_Width i.e. '9'.
311 // If dstWidth <= kNormal_Width (5), first check narrower values, then wider values.
312 // If dstWidth > kNormal_Width, first check wider values, then narrower values.
313 // When dstWidth and srcWidth are at different side of kNormal_Width,
314 // the width difference between them should be more than 5 (9/2+1)
315 constexpr int kWidthDiffThreshold = 9 / 2 + 1;
316 if (dstWidth <= normalWidth) {
317 widthDiff = (srcWidth <= dstWidth) ? (dstWidth - srcWidth)
318 : (srcWidth - dstWidth + kWidthDiffThreshold);
319 } else {
320 widthDiff = (srcWidth >= dstWidth) ? (srcWidth - dstWidth)
321 : (dstWidth - srcWidth + kWidthDiffThreshold);
322 }
323
324 constexpr int SLANT_RANGE = 3;
325 int diffSlantValue[SLANT_RANGE][SLANT_RANGE] = {
326 {0, 2, 1},
327 {2, 0, 1},
328 {2, 1, 0}
329 };
330 if (dstStyle.slant() < 0 || dstStyle.slant() >= SLANT_RANGE ||
331 srcStyle.slant() < 0 || srcStyle.slant() >= SLANT_RANGE) {
332 return 0;
333 }
334 uint32_t slantDiff = diffSlantValue[dstStyle.slant()][srcStyle.slant()];
335
336 int dstWeight = dstStyle.weight();
337 int srcWeight = srcStyle.weight();
338 uint32_t weightDiff = 0;
339
340 // The maximum weight is kExtraBlack_Weight (1000), when dstWeight and srcWeight are at the different
341 // side of kNormal_Weight, the weight difference between them should be more than 500 (1000/2)
342 constexpr int kWeightDiffThreshold = 1000 / 2;
343 if ((dstWeight == SkFontStyle::kNormal_Weight && srcWeight == SkFontStyle::kMedium_Weight) ||
344 (dstWeight == SkFontStyle::kMedium_Weight && srcWeight == SkFontStyle::kNormal_Weight)) {
345 weightDiff = 50;
346 } else if (dstWeight <= SkFontStyle::kNormal_Weight) {
347 weightDiff = (srcWeight <= dstWeight) ? (dstWeight - srcWeight)
348 : (srcWeight - dstWeight + kWeightDiffThreshold);
349 } else if (dstWeight > SkFontStyle::kNormal_Weight) {
350 weightDiff = (srcWeight >= dstWeight) ? (srcWeight - dstWeight)
351 : (dstWeight - srcWeight + kWeightDiffThreshold);
352 }
353 // The first 2 bytes to save weight difference, the third byte to save slant difference,
354 // and the fourth byte to save width difference
355 uint32_t diff = (widthDiff << 24) + (slantDiff << 16) + weightDiff;
356 return diff;
357 }
358
parseConfig(const char * fname)359 int FontConfig_OHOS::parseConfig(const char* fname)
360 {
361 if (fname == nullptr) {
362 fname = OHOS_DEFAULT_CONFIG;
363 }
364 Json::Value root;
365 int err = checkConfigFile(fname, root);
366 if (err != NO_ERROR) {
367 return err;
368 }
369
370 if (root["font_dir"].isArray()) {
371 parseFontDir(fname, root["font_dir"]);
372 }
373 if (root["fonts"].isArray()) {
374 parseFonts(root["fonts"]);
375 }
376
377 return NO_ERROR;
378 }
379
380 template<>
is() const381 bool Json::Value::is<UnicodeRange>() const
382 {
383 if (!isArray() || size() != RANGE_SIZE) {
384 return false;
385 }
386 return std::all_of(begin(), end(), [](const Value& item) { return item.isUInt(); });
387 }
388
389 template<>
as() const390 UnicodeRange Json::Value::as<UnicodeRange>() const
391 {
392 UnicodeRange res;
393 size_t index = 0;
394 for (const auto& item : *this) {
395 res[index++] = item.asUInt();
396 }
397 return res;
398 }
399
400 template<class T>
GetValue(T & v,const Json::Value & root)401 void GetValue(T& v, const Json::Value& root)
402 {
403 if (root.is<T>()) {
404 v = std::move(root.as<T>());
405 }
406 }
407
408 #define GEN_GET_FONT_FUNC(f, member) ([](FontJson&(f), const Json::Value& value) { GetValue((f).member, value); })
409
410 /*! parse the font item from the json document
411 * \param array the font array from the json document
412 * \return NO_ERROR successful
413 */
parseFonts(const Json::Value & array)414 int FontConfig_OHOS::parseFonts(const Json::Value& array)
415 {
416 const std::unordered_map<std::string, std::function<void(FontConfig_OHOS::FontJson&, const Json::Value&)>>
417 funcMap = { { "type", GEN_GET_FONT_FUNC(f, type) }, { "family", GEN_GET_FONT_FUNC(f, family) },
418 { "index", GEN_GET_FONT_FUNC(f, index) }, { "weight", GEN_GET_FONT_FUNC(f, weight) },
419 { "lang", GEN_GET_FONT_FUNC(f, lang) }, { "file", GEN_GET_FONT_FUNC(f, file) },
420 { "alias", GEN_GET_FONT_FUNC(f, alias) }, { "range", GEN_GET_FONT_FUNC(f, range)} };
421
422 for (const auto& font : array) {
423 if (!font.isObject()) {
424 continue;
425 }
426
427 FontJson f;
428 for (const auto& key : font.getMemberNames()) {
429 if (funcMap.count(key)) {
430 funcMap.at(key)(f, font[key]);
431 }
432 }
433
434 sk_sp<SkTypeface_OHOS> typeface = nullptr;
435 for (auto& dir : fFontDir) {
436 std::string path = dir + f.file;
437 if (loadFont(path.c_str(), f, typeface) == 0) {
438 fFontCollection.emplaceFont(std::move(f), std::move(typeface));
439 break;
440 }
441 }
442 }
443 forAll([this](Font& f) { sortTypefaceSet(f.typefaces); });
444 return NO_ERROR;
445 }
446
447 /*! check the system font configuration document
448 * \param fname the full name of the font configuration document
449 * \return NO_ERROR successful
450 * \return ERROR_CONFIG_NOT_FOUND config document is not found
451 * \return ERROR_CONFIG_FORMAT_NOT_SUPPORTED config document format is not supported
452 */
checkConfigFile(const char * fname,Json::Value & root)453 int FontConfig_OHOS::checkConfigFile(const char* fname, Json::Value& root)
454 {
455 std::ifstream fstream(fname);
456
457 if (!fstream.is_open()) {
458 return ERROR_CONFIG_NOT_FOUND;
459 }
460
461 Json::Reader reader;
462 bool isJson = reader.parse(fstream, root, false);
463 if (!isJson) {
464 return ERROR_CONFIG_FORMAT_NOT_SUPPORTED;
465 }
466 return NO_ERROR;
467 }
468
469 /*! To parse 'fontdir' attribute
470 * \param root the root node of 'fontdir'
471 * \return NO_ERROR successful
472 */
parseFontDir(const char * fname,const Json::Value & root)473 int FontConfig_OHOS::parseFontDir(const char* fname, const Json::Value& root)
474 {
475 for (auto& path : root) {
476 if (!path.isString()) {
477 continue;
478 }
479 std::string dir;
480 #ifdef SK_BUILD_FONT_MGR_FOR_PREVIEW
481 if (strcmp(fname, OHOS_DEFAULT_CONFIG) == 0) {
482 dir = (path.asString() != "/system/fonts/") ? path.asString() : "fonts/";
483 } else {
484 dir = (path.asString() != "/system/fonts/")
485 ? path.asString() : "../../../../hms/previewer/resources/fonts/";
486 }
487 #else
488 dir = path.asString();
489 #endif
490 fFontDir.push_back(std::move(dir));
491 }
492 return NO_ERROR;
493 }
494
495 /*! To load font information from a font file
496 * \param fname the full name of a font file
497 * \param info the font information read from json document
498 * \param typeface the typeface to be loaded
499 * \return NO_ERROR successful
500 * \return ERROR_FONT_NOT_EXIST font file is not exist
501 * \return ERROR_FONT_INVALID_STREAM the stream is not recognized
502 */
loadFont(const char * fname,FontJson & info,sk_sp<SkTypeface_OHOS> & typeface)503 int FontConfig_OHOS::loadFont(const char* fname, FontJson& info, sk_sp<SkTypeface_OHOS>& typeface) {
504 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(fname);
505 if (stream == nullptr) {
506 return ERROR_FONT_NOT_EXIST;
507 }
508 FontInfo font(fname, info.index);
509 if (!fFontScanner.scanFont(stream.get(), info.index, &font.familyName, &font.style, &font.isFixedWidth, nullptr)) {
510 return ERROR_FONT_INVALID_STREAM;
511 }
512
513 const char* temp = (info.type == FontType::Generic) ? info.alias.c_str() : "";
514 SkString family(temp);
515 typeface = sk_make_sp<SkTypeface_OHOS>(family, font);
516 return NO_ERROR;
517 }
518
loadHMSymbol()519 void FontConfig_OHOS::loadHMSymbol()
520 {
521 if (!G_IS_HMSYMBOL_ENABLE) {
522 return;
523 }
524 for (auto& dir : fFontDir) {
525 if (skia::text::HmSymbolConfig_OHOS::LoadSymbolConfig(
526 "hm_symbol_config_next.json", SkString(dir.c_str())) == NO_ERROR) {
527 return;
528 }
529 }
530 }
531
532 /*! To sort the typeface set
533 * \param typefaceSet the typeface set to be sorted
534 */
sortTypefaceSet(std::vector<sk_sp<SkTypeface_OHOS>> & typefaceSet)535 void FontConfig_OHOS::sortTypefaceSet(std::vector<sk_sp<SkTypeface_OHOS>>& typefaceSet)
536 {
537 std::sort(typefaceSet.begin(), typefaceSet.end(), [](const auto& a, const auto& b) {
538 return (a->fontStyle().weight() < b->fontStyle().weight()) ||
539 (a->fontStyle().weight() == b->fontStyle().weight() && a->fontStyle().slant() < b->fontStyle().slant());
540 });
541 }
542
judgeFileExist()543 bool FontConfig_OHOS::judgeFileExist()
544 {
545 bool haveFile = false;
546 for (const auto& path : fFontDir) {
547 DIR* dir = opendir(path.c_str());
548 if (dir == nullptr) {
549 continue;
550 }
551 struct dirent* node = nullptr;
552 #if defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_WIN)
553 struct stat fileStat;
554 #endif
555 while ((node = readdir(dir))) {
556 #if defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_WIN)
557 stat(node->d_name, &fileStat);
558 if (S_ISDIR(fileStat.st_mode)) {
559 continue;
560 }
561 #else
562 if (node->d_type != DT_REG) {
563 continue;
564 }
565 #endif
566 const char* fileName = node->d_name;
567 int len = strlen(fileName);
568 int suffixLen = strlen(".ttf");
569 if (len < suffixLen ||
570 (strncmp(fileName + len - suffixLen, ".ttf", suffixLen) != 0 &&
571 strncmp(fileName + len - suffixLen, ".otf", suffixLen) != 0 &&
572 strncmp(fileName + len - suffixLen, ".ttc", suffixLen) != 0 &&
573 strncmp(fileName + len - suffixLen, ".otc", suffixLen) != 0)) {
574 continue;
575 }
576 haveFile = true;
577 break;
578 }
579 (void)closedir(dir);
580 if (haveFile) {
581 break;
582 }
583 }
584 return haveFile;
585 }
586
checkProductFile(const char * fname)587 int FontConfig_OHOS::checkProductFile(const char* fname)
588 {
589 std::lock_guard<std::mutex> lock(fFontMutex);
590 int err = parseConfig(PRODUCT_DEFAULT_CONFIG);
591 if (err != NO_ERROR || !judgeFileExist()) {
592 err = parseConfig(OHOS_DEFAULT_CONFIG);
593 }
594 return err;
595 }
596
Font(FontJson & info)597 FontConfig_OHOS::Font::Font(FontJson& info)
598 : slant(info.slant), weight(info.weight), alias(info.alias), family(info.family), lang(info.lang)
599 {
600 this->type = info.type >= FontType::NumOfFontType ? FontType::Generic : static_cast<FontType>(info.type);
601 }
602
containRange(const UnicodeRange & range,size_t index)603 bool FontConfig_OHOS::containRange(const UnicodeRange& range, size_t index)
604 {
605 // because the range is 11 32-bit, so we need to / 32 means >> 5
606 int16_t i = index >> 5;
607 // get the bit position by mod 32 which means & 31
608 int16_t bit = index & 31;
609 return ((range[i] >> bit) & 1) != 0;
610 }
611
emplaceFont(FontJson && fj,sk_sp<SkTypeface_OHOS> && typeface)612 void FontConfig_OHOS::FontCollection::emplaceFont(FontJson&& fj, sk_sp<SkTypeface_OHOS>&& typeface)
613 {
614 if (fj.family.empty()) {
615 return;
616 }
617 Font f(fj);
618 auto& targetVec = (f.type == FontType::Generic) ? fGeneric : fFallback;
619 auto& targetName = (f.type == FontType::Generic) ? f.alias : f.family;
620 // generic must have alias
621 auto exist = fIndexMap.find(targetName);
622 // if not found, insert directly
623 if (exist == fIndexMap.end()) {
624 for (size_t i = 0; i < UNICODE_RANGE_SIZE && f.type == FontType::Fallback; i += 1) {
625 if (containRange(fj.range, i)) {
626 fRangeToIndex[i].push_back(targetVec.size());
627 }
628 }
629 fIndexMap.emplace(targetName, std::make_pair(targetVec.size(), f.type));
630 targetVec.emplace_back(f);
631 targetVec.back().typefaces.emplace_back(typeface);
632 } else {
633 // if exist, add the typeface to the font
634 targetVec[exist->second.first].typefaces.emplace_back(typeface);
635 }
636 }
637
getIndexByFamilyName(const std::string & family,std::pair<size_t,FontType> & res) const638 bool FontConfig_OHOS::FontCollection::getIndexByFamilyName(
639 const std::string& family, std::pair<size_t, FontType>& res) const
640 {
641 if (fIndexMap.count(family)) {
642 res = fIndexMap.at(family);
643 return true;
644 }
645 return false;
646 }
647
getSet(bool isFallback) const648 const std::vector<FontConfig_OHOS::Font>& FontConfig_OHOS::FontCollection::getSet(bool isFallback) const
649 {
650 return isFallback ? fFallback : fGeneric;
651 }
652
forAll(std::function<void (FontConfig_OHOS::Font &)> func)653 void FontConfig_OHOS::FontCollection::forAll(std::function<void(FontConfig_OHOS::Font&)> func)
654 {
655 for (auto& f : fFallback) {
656 func(f);
657 }
658 for (auto& f : fGeneric) {
659 func(f);
660 }
661 }
662
charRangeIndex(SkUnichar unicode)663 int16_t FontConfig_OHOS::charRangeIndex(SkUnichar unicode)
664 {
665 auto it = fRangeMap.upper_bound({ unicode, UINT32_MAX });
666 if (it != fRangeMap.begin()) {
667 --it;
668 }
669 if (unicode >= it->first.first && unicode <= it->first.second) {
670 return it->second;
671 }
672 return -1;
673 }
674
675 const std::map<std::pair<uint32_t, uint32_t>, int16_t> FontConfig_OHOS::fRangeMap {
676 { { 0x0, 0x7F }, 0 },
677 { { 0x80, 0xFF }, 1 },
678 { { 0x100, 0x17F }, 2 },
679 { { 0x180, 0x24F }, 3 },
680 { { 0x250, 0x2AF }, 4 },
681 { { 0x2B0, 0x2FF }, 5 },
682 { { 0x300, 0x36F }, 6 },
683 { { 0x370, 0x3FF }, 7 },
684 { { 0x400, 0x4FF }, 8 },
685 { { 0x500, 0x52F }, 9 },
686 { { 0x530, 0x58F }, 10 },
687 { { 0x590, 0x5FF }, 11 },
688 { { 0x600, 0x6FF }, 12 },
689 { { 0x700, 0x74F }, 13 },
690 { { 0x750, 0x77F }, 14 },
691 { { 0x780, 0x7BF }, 15 },
692 { { 0x7C0, 0x7FF }, 16 },
693 { { 0x800, 0x83F }, 17 },
694 { { 0x840, 0x85F }, 18 },
695 { { 0x860, 0x86F }, 19 },
696 { { 0x870, 0x89F }, 20 },
697 { { 0x8A0, 0x8FF }, 21 },
698 { { 0x900, 0x97F }, 22 },
699 { { 0x980, 0x9FF }, 23 },
700 { { 0xA00, 0xA7F }, 24 },
701 { { 0xA80, 0xAFF }, 25 },
702 { { 0xB00, 0xB7F }, 26 },
703 { { 0xB80, 0xBFF }, 27 },
704 { { 0xC00, 0xC7F }, 28 },
705 { { 0xC80, 0xCFF }, 29 },
706 { { 0xD00, 0xD7F }, 30 },
707 { { 0xD80, 0xDFF }, 31 },
708 { { 0xE00, 0xE7F }, 32 },
709 { { 0xE80, 0xEFF }, 33 },
710 { { 0xF00, 0xFFF }, 34 },
711 { { 0x1000, 0x109F }, 35 },
712 { { 0x10A0, 0x10FF }, 36 },
713 { { 0x1100, 0x11FF }, 37 },
714 { { 0x1200, 0x137F }, 38 },
715 { { 0x1380, 0x139F }, 39 },
716 { { 0x13A0, 0x13FF }, 40 },
717 { { 0x1400, 0x167F }, 41 },
718 { { 0x1680, 0x169F }, 42 },
719 { { 0x16A0, 0x16FF }, 43 },
720 { { 0x1700, 0x171F }, 44 },
721 { { 0x1720, 0x173F }, 45 },
722 { { 0x1740, 0x175F }, 46 },
723 { { 0x1760, 0x177F }, 47 },
724 { { 0x1780, 0x17FF }, 48 },
725 { { 0x1800, 0x18AF }, 49 },
726 { { 0x18B0, 0x18FF }, 50 },
727 { { 0x1900, 0x194F }, 51 },
728 { { 0x1950, 0x197F }, 52 },
729 { { 0x1980, 0x19DF }, 53 },
730 { { 0x19E0, 0x19FF }, 54 },
731 { { 0x1A00, 0x1A1F }, 55 },
732 { { 0x1A20, 0x1AAF }, 56 },
733 { { 0x1AB0, 0x1AFF }, 57 },
734 { { 0x1B00, 0x1B7F }, 58 },
735 { { 0x1B80, 0x1BBF }, 59 },
736 { { 0x1BC0, 0x1BFF }, 60 },
737 { { 0x1C00, 0x1C4F }, 61 },
738 { { 0x1C50, 0x1C7F }, 62 },
739 { { 0x1C80, 0x1C8F }, 63 },
740 { { 0x1C90, 0x1CBF }, 64 },
741 { { 0x1CC0, 0x1CCF }, 65 },
742 { { 0x1CD0, 0x1CFF }, 66 },
743 { { 0x1D00, 0x1D7F }, 67 },
744 { { 0x1D80, 0x1DBF }, 68 },
745 { { 0x1DC0, 0x1DFF }, 69 },
746 { { 0x1E00, 0x1EFF }, 70 },
747 { { 0x1F00, 0x1FFF }, 71 },
748 { { 0x2000, 0x206F }, 72 },
749 { { 0x2070, 0x209F }, 73 },
750 { { 0x20A0, 0x20CF }, 74 },
751 { { 0x20D0, 0x20FF }, 75 },
752 { { 0x2100, 0x214F }, 76 },
753 { { 0x2150, 0x218F }, 77 },
754 { { 0x2190, 0x21FF }, 78 },
755 { { 0x2200, 0x22FF }, 79 },
756 { { 0x2300, 0x23FF }, 80 },
757 { { 0x2400, 0x243F }, 81 },
758 { { 0x2440, 0x245F }, 82 },
759 { { 0x2460, 0x24FF }, 83 },
760 { { 0x2500, 0x257F }, 84 },
761 { { 0x2580, 0x259F }, 85 },
762 { { 0x25A0, 0x25FF }, 86 },
763 { { 0x2600, 0x26FF }, 87 },
764 { { 0x2700, 0x27BF }, 88 },
765 { { 0x27C0, 0x27EF }, 89 },
766 { { 0x27F0, 0x27FF }, 90 },
767 { { 0x2800, 0x28FF }, 91 },
768 { { 0x2900, 0x297F }, 92 },
769 { { 0x2980, 0x29FF }, 93 },
770 { { 0x2A00, 0x2AFF }, 94 },
771 { { 0x2B00, 0x2BFF }, 95 },
772 { { 0x2C00, 0x2C5F }, 96 },
773 { { 0x2C60, 0x2C7F }, 97 },
774 { { 0x2C80, 0x2CFF }, 98 },
775 { { 0x2D00, 0x2D2F }, 99 },
776 { { 0x2D30, 0x2D7F }, 100 },
777 { { 0x2D80, 0x2DDF }, 101 },
778 { { 0x2DE0, 0x2DFF }, 102 },
779 { { 0x2E00, 0x2E7F }, 103 },
780 { { 0x2E80, 0x2EFF }, 104 },
781 { { 0x2F00, 0x2FDF }, 105 },
782 { { 0x2FF0, 0x2FFF }, 106 },
783 { { 0x3000, 0x303F }, 107 },
784 { { 0x3040, 0x309F }, 108 },
785 { { 0x30A0, 0x30FF }, 109 },
786 { { 0x3100, 0x312F }, 110 },
787 { { 0x3130, 0x318F }, 111 },
788 { { 0x3190, 0x319F }, 112 },
789 { { 0x31A0, 0x31BF }, 113 },
790 { { 0x31C0, 0x31EF }, 114 },
791 { { 0x31F0, 0x31FF }, 115 },
792 { { 0x3200, 0x32FF }, 116 },
793 { { 0x3300, 0x33FF }, 117 },
794 { { 0x3400, 0x4DBF }, 118 },
795 { { 0x4DC0, 0x4DFF }, 119 },
796 { { 0x4E00, 0x9FFF }, 120 },
797 { { 0xA000, 0xA48F }, 121 },
798 { { 0xA490, 0xA4CF }, 122 },
799 { { 0xA4D0, 0xA4FF }, 123 },
800 { { 0xA500, 0xA63F }, 124 },
801 { { 0xA640, 0xA69F }, 125 },
802 { { 0xA6A0, 0xA6FF }, 126 },
803 { { 0xA700, 0xA71F }, 127 },
804 { { 0xA720, 0xA7FF }, 128 },
805 { { 0xA800, 0xA82F }, 129 },
806 { { 0xA830, 0xA83F }, 130 },
807 { { 0xA840, 0xA87F }, 131 },
808 { { 0xA880, 0xA8DF }, 132 },
809 { { 0xA8E0, 0xA8FF }, 133 },
810 { { 0xA900, 0xA92F }, 134 },
811 { { 0xA930, 0xA95F }, 135 },
812 { { 0xA960, 0xA97F }, 136 },
813 { { 0xA980, 0xA9DF }, 137 },
814 { { 0xA9E0, 0xA9FF }, 138 },
815 { { 0xAA00, 0xAA5F }, 139 },
816 { { 0xAA60, 0xAA7F }, 140 },
817 { { 0xAA80, 0xAADF }, 141 },
818 { { 0xAAE0, 0xAAFF }, 142 },
819 { { 0xAB00, 0xAB2F }, 143 },
820 { { 0xAB30, 0xAB6F }, 144 },
821 { { 0xAB70, 0xABBF }, 145 },
822 { { 0xABC0, 0xABFF }, 146 },
823 { { 0xAC00, 0xD7AF }, 147 },
824 { { 0xD7B0, 0xD7FF }, 148 },
825 { { 0xD800, 0xDB7F }, 149 },
826 { { 0xDB80, 0xDBFF }, 150 },
827 { { 0xDC00, 0xDFFF }, 151 },
828 { { 0xE000, 0xF8FF }, 152 },
829 { { 0xF900, 0xFAFF }, 153 },
830 { { 0xFB00, 0xFB4F }, 154 },
831 { { 0xFB50, 0xFDFF }, 155 },
832 { { 0xFE00, 0xFE0F }, 156 },
833 { { 0xFE10, 0xFE1F }, 157 },
834 { { 0xFE20, 0xFE2F }, 158 },
835 { { 0xFE30, 0xFE4F }, 159 },
836 { { 0xFE50, 0xFE6F }, 160 },
837 { { 0xFE70, 0xFEFF }, 161 },
838 { { 0xFF00, 0xFFEF }, 162 },
839 { { 0xFFF0, 0xFFFF }, 163 },
840 { { 0x10000, 0x1007F }, 164 },
841 { { 0x10080, 0x100FF }, 165 },
842 { { 0x10100, 0x1013F }, 166 },
843 { { 0x10140, 0x1018F }, 167 },
844 { { 0x10190, 0x101CF }, 168 },
845 { { 0x101D0, 0x101FF }, 169 },
846 { { 0x10280, 0x1029F }, 170 },
847 { { 0x102A0, 0x102DF }, 171 },
848 { { 0x102E0, 0x102FF }, 172 },
849 { { 0x10300, 0x1032F }, 173 },
850 { { 0x10330, 0x1034F }, 174 },
851 { { 0x10350, 0x1037F }, 175 },
852 { { 0x10380, 0x1039F }, 176 },
853 { { 0x103A0, 0x103DF }, 177 },
854 { { 0x10400, 0x1044F }, 178 },
855 { { 0x10450, 0x1047F }, 179 },
856 { { 0x10480, 0x104AF }, 180 },
857 { { 0x104B0, 0x104FF }, 181 },
858 { { 0x10500, 0x1052F }, 182 },
859 { { 0x10530, 0x1056F }, 183 },
860 { { 0x10570, 0x105BF }, 184 },
861 { { 0x10600, 0x1077F }, 185 },
862 { { 0x10780, 0x107BF }, 186 },
863 { { 0x10800, 0x1083F }, 187 },
864 { { 0x10840, 0x1085F }, 188 },
865 { { 0x10860, 0x1087F }, 189 },
866 { { 0x10880, 0x108AF }, 190 },
867 { { 0x108E0, 0x108FF }, 191 },
868 { { 0x10900, 0x1091F }, 192 },
869 { { 0x10920, 0x1093F }, 193 },
870 { { 0x10980, 0x1099F }, 194 },
871 { { 0x109A0, 0x109FF }, 195 },
872 { { 0x10A00, 0x10A5F }, 196 },
873 { { 0x10A60, 0x10A7F }, 197 },
874 { { 0x10A80, 0x10A9F }, 198 },
875 { { 0x10AC0, 0x10AFF }, 199 },
876 { { 0x10B00, 0x10B3F }, 200 },
877 { { 0x10B40, 0x10B5F }, 201 },
878 { { 0x10B60, 0x10B7F }, 202 },
879 { { 0x10B80, 0x10BAF }, 203 },
880 { { 0x10C00, 0x10C4F }, 204 },
881 { { 0x10C80, 0x10CFF }, 205 },
882 { { 0x10D00, 0x10D3F }, 206 },
883 { { 0x10E60, 0x10E7F }, 207 },
884 { { 0x10E80, 0x10EBF }, 208 },
885 { { 0x10EC0, 0x10EFF }, 209 },
886 { { 0x10F00, 0x10F2F }, 210 },
887 { { 0x10F30, 0x10F6F }, 211 },
888 { { 0x10F70, 0x10FAF }, 212 },
889 { { 0x10FB0, 0x10FDF }, 213 },
890 { { 0x10FE0, 0x10FFF }, 214 },
891 { { 0x11000, 0x1107F }, 215 },
892 { { 0x11080, 0x110CF }, 216 },
893 { { 0x110D0, 0x110FF }, 217 },
894 { { 0x11100, 0x1114F }, 218 },
895 { { 0x11150, 0x1117F }, 219 },
896 { { 0x11180, 0x111DF }, 220 },
897 { { 0x111E0, 0x111FF }, 221 },
898 { { 0x11200, 0x1124F }, 222 },
899 { { 0x11280, 0x112AF }, 223 },
900 { { 0x112B0, 0x112FF }, 224 },
901 { { 0x11300, 0x1137F }, 225 },
902 { { 0x11400, 0x1147F }, 226 },
903 { { 0x11480, 0x114DF }, 227 },
904 { { 0x11580, 0x115FF }, 228 },
905 { { 0x11600, 0x1165F }, 229 },
906 { { 0x11660, 0x1167F }, 230 },
907 { { 0x11680, 0x116CF }, 231 },
908 { { 0x116D0, 0x116FF }, 232 },
909 { { 0x11700, 0x1174F }, 233 },
910 { { 0x11800, 0x1184F }, 234 },
911 { { 0x118A0, 0x118FF }, 235 },
912 { { 0x11900, 0x1195F }, 236 },
913 { { 0x119A0, 0x119FF }, 237 },
914 { { 0x11A00, 0x11A4F }, 238 },
915 { { 0x11A50, 0x11AAF }, 239 },
916 { { 0x11AB0, 0x11ABF }, 240 },
917 { { 0x11AC0, 0x11AFF }, 241 },
918 { { 0x11B00, 0x11B5F }, 242 },
919 { { 0x11C00, 0x11C6F }, 243 },
920 { { 0x11C70, 0x11CBF }, 244 },
921 { { 0x11D00, 0x11D5F }, 245 },
922 { { 0x11D60, 0x11DAF }, 246 },
923 { { 0x11EE0, 0x11EFF }, 247 },
924 { { 0x11F00, 0x11F5F }, 248 },
925 { { 0x11FB0, 0x11FBF }, 249 },
926 { { 0x11FC0, 0x11FFF }, 250 },
927 { { 0x12000, 0x123FF }, 251 },
928 { { 0x12400, 0x1247F }, 252 },
929 { { 0x12480, 0x1254F }, 253 },
930 { { 0x12F90, 0x12FFF }, 254 },
931 { { 0x13000, 0x1342F }, 255 },
932 { { 0x13430, 0x1345F }, 256 },
933 { { 0x14400, 0x1467F }, 257 },
934 { { 0x16800, 0x16A3F }, 258 },
935 { { 0x16A40, 0x16A6F }, 259 },
936 { { 0x16A70, 0x16ACF }, 260 },
937 { { 0x16AD0, 0x16AFF }, 261 },
938 { { 0x16B00, 0x16B8F }, 262 },
939 { { 0x16D40, 0x16D7F }, 263 },
940 { { 0x16E40, 0x16E9F }, 264 },
941 { { 0x16F00, 0x16F9F }, 265 },
942 { { 0x16FE0, 0x16FFF }, 266 },
943 { { 0x17000, 0x187FF }, 267 },
944 { { 0x18800, 0x18AFF }, 268 },
945 { { 0x18B00, 0x18CFF }, 269 },
946 { { 0x18D00, 0x18D7F }, 270 },
947 { { 0x1AFF0, 0x1AFFF }, 271 },
948 { { 0x1B000, 0x1B0FF }, 272 },
949 { { 0x1B100, 0x1B12F }, 273 },
950 { { 0x1B130, 0x1B16F }, 274 },
951 { { 0x1B170, 0x1B2FF }, 275 },
952 { { 0x1BC00, 0x1BC9F }, 276 },
953 { { 0x1BCA0, 0x1BCAF }, 277 },
954 { { 0x1CC00, 0x1CEBF }, 278 },
955 { { 0x1CF00, 0x1CFCF }, 279 },
956 { { 0x1D000, 0x1D0FF }, 280 },
957 { { 0x1D100, 0x1D1FF }, 281 },
958 { { 0x1D200, 0x1D24F }, 282 },
959 { { 0x1D2C0, 0x1D2DF }, 283 },
960 { { 0x1D2E0, 0x1D2FF }, 284 },
961 { { 0x1D300, 0x1D35F }, 285 },
962 { { 0x1D360, 0x1D37F }, 286 },
963 { { 0x1D400, 0x1D7FF }, 287 },
964 { { 0x1D800, 0x1DAAF }, 288 },
965 { { 0x1DF00, 0x1DFFF }, 289 },
966 { { 0x1E000, 0x1E02F }, 290 },
967 { { 0x1E030, 0x1E08F }, 291 },
968 { { 0x1E100, 0x1E14F }, 292 },
969 { { 0x1E290, 0x1E2BF }, 293 },
970 { { 0x1E2C0, 0x1E2FF }, 294 },
971 { { 0x1E4D0, 0x1E4FF }, 295 },
972 { { 0x1E5D0, 0x1E5FF }, 296 },
973 { { 0x1E7E0, 0x1E7FF }, 297 },
974 { { 0x1E800, 0x1E8DF }, 298 },
975 { { 0x1E900, 0x1E95F }, 299 },
976 { { 0x1EC70, 0x1ECBF }, 300 },
977 { { 0x1ED00, 0x1ED4F }, 301 },
978 { { 0x1EE00, 0x1EEFF }, 302 },
979 { { 0x1F000, 0x1F02F }, 303 },
980 { { 0x1F030, 0x1F09F }, 304 },
981 { { 0x1F0A0, 0x1F0FF }, 305 },
982 { { 0x1F100, 0x1F1FF }, 306 },
983 { { 0x1F200, 0x1F2FF }, 307 },
984 { { 0x1F300, 0x1F5FF }, 308 },
985 { { 0x1F600, 0x1F64F }, 309 },
986 { { 0x1F650, 0x1F67F }, 310 },
987 { { 0x1F680, 0x1F6FF }, 311 },
988 { { 0x1F700, 0x1F77F }, 312 },
989 { { 0x1F780, 0x1F7FF }, 313 },
990 { { 0x1F800, 0x1F8FF }, 314 },
991 { { 0x1F900, 0x1F9FF }, 315 },
992 { { 0x1FA00, 0x1FA6F }, 316 },
993 { { 0x1FA70, 0x1FAFF }, 317 },
994 { { 0x1FB00, 0x1FBFF }, 318 },
995 { { 0x20000, 0x2A6DF }, 319 },
996 { { 0x2A700, 0x2B73F }, 320 },
997 { { 0x2B740, 0x2B81F }, 321 },
998 { { 0x2B820, 0x2CEAF }, 322 },
999 { { 0x2CEB0, 0x2EBEF }, 323 },
1000 { { 0x2EBF0, 0x2EE5F }, 324 },
1001 { { 0x2F800, 0x2FA1F }, 325 },
1002 { { 0x30000, 0x3134F }, 326 },
1003 { { 0x31350, 0x323AF }, 327 },
1004 { { 0xE0000, 0xE007F }, 328 },
1005 { { 0xE0100, 0xE01EF }, 329 },
1006 { { 0xF0000, 0xFFFFF }, 330 },
1007 { { 0x100000, 0x10FFFF }, 331 },
1008 };
1009
1010 #endif // ENABLE_TEXT_ENHANCE