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 <algorithm>
8 #include <array>
9 #include <cstring>
10 #include <dirent.h>
11 #include <fstream>
12 #include <functional>
13 #include <libgen.h>
14 #include <sys/stat.h>
15 #include <sys/types.h>
16 #include <unistd.h>
17
18 #if defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_WIN) or defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_MAC) or \
19 defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_LINUX)
20 #define SK_BUILD_FONT_MGR_FOR_PREVIEW
21 #endif
22
23 #ifdef SK_BUILD_FONT_MGR_FOR_OHOS
24 #include <parameters.h>
25 #endif
26
27 #include "SkFontStyle.h"
28 #include "SkString.h"
29 #include "securec.h"
30
31 using namespace ErrorCode;
32 static const char* PRODUCT_DEFAULT_CONFIG = "/system/etc/productfontconfig.json";
33
34 #ifdef SK_BUILD_FONT_MGR_FOR_OHOS
35 static const bool G_IS_HMSYMBOL_ENABLE =
36 (std::atoi(OHOS::system::GetParameter("persist.sys.graphic.hmsymbolcfg.enable", "1").c_str()) != 0);
37 #else
38 static const bool G_IS_HMSYMBOL_ENABLE = true;
39 #endif
40
41 #ifdef SK_BUILD_FONT_MGR_FOR_PREVIEW
42 static const char* OHOS_DEFAULT_CONFIG = "fontconfig_ohos.json";
43 /*! Constructor
44 * \param fontScanner the scanner to get the font information from a font file
45 * \param fname the full name of system font configuration document.
46 * \n The default value is '/system/etc/fontconfig_ohos.json', if fname is given null
47 */
FontConfig_OHOS(const SkTypeface_FreeType::Scanner & fontScanner,const char * fname)48 FontConfig_OHOS::FontConfig_OHOS(const SkTypeface_FreeType::Scanner& fontScanner, const char* fname)
49 : fFontScanner(fontScanner)
50 {
51 int err = parseConfig(fname);
52 if (err != NO_ERROR) {
53 return;
54 }
55 loadHMSymbol();
56 }
57 #else
58 static const char* OHOS_DEFAULT_CONFIG = "/system/etc/fontconfig_ohos.json";
59 /*! Constructor
60 * \param fontScanner the scanner to get the font information from a font file
61 * \param fname the full name of system font configuration document.
62 * \n The default value is '/system/etc/fontconfig_ohos.json', if fname is given null
63 */
FontConfig_OHOS(const SkTypeface_FreeType::Scanner & fontScanner,const char * fname)64 FontConfig_OHOS::FontConfig_OHOS(const SkTypeface_FreeType::Scanner& fontScanner, const char* fname)
65 : fFontScanner(fontScanner)
66 {
67 int err = checkProductFile(fname);
68 if (err != NO_ERROR) {
69 return;
70 }
71 loadHMSymbol();
72 }
73 #endif
74
75 /*! To get the count of font style sets supported in the system
76 * \return The count of font style sets in generic family
77 */
getFamilyCount() const78 int FontConfig_OHOS::getFamilyCount() const
79 {
80 return fFontCollection.fGeneric.size();
81 }
82
83 /*! To match the fallback typeface by the given style and character
84 * this function will traverse all the fallback typefaces
85 * \param character the character to be matched
86 * \param style the style to be matched
87 * \return the matched typeface
88 */
matchFallback(SkUnichar character,const SkFontStyle & style) const89 SkTypeface* FontConfig_OHOS::matchFallback(SkUnichar character, const SkFontStyle& style) const
90 {
91 // find the fallback typeface at emoji first
92 const auto& emoji = getFallbackTypeface(SkString("HMOS Color Emoji"), style);
93 if (emoji && emoji->unicharToGlyph(character)) {
94 return SkSafeRef(emoji.get());
95 }
96
97 for (auto& f : fFontCollection.fFallback) {
98 const auto& typefaces = f.typefaces;
99 // for the compatibility to the old version
100 if (!typefaces.empty() && (f.containChar(character) || f.family.find("JP") != std::string::npos)) {
101 if (!typefaces[0]->unicharToGlyph(character)) {
102 continue;
103 }
104 return SkSafeRef(matchFontStyle(typefaces, style).get());
105 }
106 }
107
108 // find the fallback typeface at emoji flags third
109 const auto& flags = getFallbackTypeface(SkString("HMOS Color Emoji Flags"), style);
110 if (flags && flags->unicharToGlyph(character)) {
111 return SkSafeRef(flags.get());
112 }
113
114 for (auto& f : fFontCollection.fFallback) {
115 const auto& typefaces = f.typefaces;
116 if (!typefaces.empty() && typefaces[0]->unicharToGlyph(character)) {
117 return SkSafeRef(matchFontStyle(typefaces, style).get());
118 }
119 }
120 return nullptr;
121 }
122
123
124 /*! To match the fallback typeface by the given index style and character
125 * this function only traverse the fallback typefaces in the given index
126 * \param index the index of fallback typefaces
127 * \param character the character to be matched
128 * \param style the style to be matched
129 * \return the matched typeface
130 */
matchFallback(size_t index,SkUnichar character,const SkFontStyle & style) const131 SkTypeface* FontConfig_OHOS::matchFallback(size_t index, SkUnichar character, const SkFontStyle& style) const
132 {
133 if (index >= fFontCollection.fFallback.size()) {
134 return nullptr;
135 }
136 const auto& typefaces = fFontCollection.fFallback[index].typefaces;
137 if (!typefaces.empty() && typefaces[0]->unicharToGlyph(character)) {
138 auto typeface = matchFontStyle(typefaces, style);
139 return SkSafeRef(typeface.get());
140 }
141 return nullptr;
142 }
143
144 /*! To match the fallback typeface by the given function
145 * this function will traverse all the fallback typefaces
146 * \param func the judge func, if the func return -1, it means the language tag is not matched
147 * \return the matched fallback typefaces' index set
148 */
matchFallbackByBCP47(std::function<int (const std::string &)> func) const149 std::vector<size_t> FontConfig_OHOS::matchFallbackByBCP47(std::function<int(const std::string&)> func) const
150 {
151 std::vector<size_t> res;
152 for (size_t i = 0; i < fFontCollection.fFallback.size(); i += 1) {
153 if (func(fFontCollection.fFallback[i].lang) != -1) {
154 res.push_back(i);
155 }
156 }
157 return res;
158 }
159
160 /*! To get a typeface by the given family name and style
161 * this function will traverse both the fallback and general typefaces
162 * \param familyName the family name of the fallback typeface
163 * \param style the style of the fallback typeface
164 * \return the matched typeface
165 */
getFallbackTypeface(const SkString & familyName,const SkFontStyle & style) const166 sk_sp<SkTypeface_OHOS> FontConfig_OHOS::getFallbackTypeface(const SkString& familyName, const SkFontStyle& style) const
167 {
168 std::pair<size_t, FontType> res;
169 if (!fFontCollection.getIndexByFamilyName(familyName.c_str(), res)) {
170 return nullptr;
171 }
172
173 const auto& tpSet = fFontCollection.getSet(true)[res.first].typefaces;
174 if (tpSet.size() == 0) {
175 return nullptr;
176 }
177 return FontConfig_OHOS::matchFontStyle(tpSet, style);
178 }
179
180 /*! To get the family name of the default font style set
181 * \param[out] familyName a pointer of SkString object, to which the family value will be set.
182 * \return The count of typeface in this font style set
183 * \n Return -1, if there is no any font style set in the system.
184 */
getDefaultFamily(SkString & familyName) const185 int FontConfig_OHOS::getDefaultFamily(SkString& familyName) const
186 {
187 return getFamilyName(0, familyName);
188 }
189
190 /*! To get the family name of a font style set
191 * \param index the index of a font style set in generic family
192 * \param[out] familyName a pointer of SkString object, to which the family value will be set
193 * \return The count of typeface in the font style set
194 * \n Return -1, if the 'index' is out of range
195 */
getFamilyName(size_t index,SkString & familyName) const196 int FontConfig_OHOS::getFamilyName(size_t index, SkString& familyName) const
197 {
198 if (index >= getFamilyCount()) {
199 familyName = "";
200 return -1;
201 }
202 familyName = fFontCollection.fGeneric[index].alias.c_str();
203 return fFontCollection.fGeneric[index].typefaces.size();
204 }
205
206 /*! To get the count of a font style set
207 * \param styleIndex the index of a font style set
208 * \param isFallback to indicate the font style set is from generic family or fallback family
209 * \n false , the font style set is from generic family list
210 * \n true, the font style set is from fallback family list
211 * \return The count of typeface in the font style set
212 */
getTypefaceCount(size_t styleIndex,bool isFallback) const213 size_t FontConfig_OHOS::getTypefaceCount(size_t styleIndex, bool isFallback) const
214 {
215 auto& set = fFontCollection.getSet(isFallback);
216 return (styleIndex < set.size()) ? set[styleIndex].typefaces.size() : 0;
217 }
218
219 /*! To get a typeface
220 * \param styleIndex the index of a font style set
221 * \param index the index of a typeface in its style set
222 * \param isFallback false, the font style set is generic
223 * \n true, the font style set is fallback
224 * \return The pointer of a typeface
225 * \n Return null, if 'styleIndex' or 'index' is out of range
226 */
getTypeface(size_t styleIndex,size_t index,bool isFallback) const227 SkTypeface_OHOS* FontConfig_OHOS::getTypeface(size_t styleIndex, size_t index, bool isFallback) const
228 {
229 sk_sp<SkTypeface_OHOS> typeface = getTypefaceSP(styleIndex, index, isFallback);
230 return (typeface == nullptr) ? nullptr : typeface.get();
231 }
232
getTypefaceSP(size_t styleIndex,size_t index,bool isFallback) const233 sk_sp<SkTypeface_OHOS> FontConfig_OHOS::getTypefaceSP(size_t styleIndex, size_t index, bool isFallback) const
234 {
235 auto& fontSet = fFontCollection.getSet(isFallback);
236 if (styleIndex <= fontSet.size()) {
237 // if index less than typefaces' size, return the ptr
238 return (index < fontSet[styleIndex].typefaces.size()) ? fontSet[styleIndex].typefaces[index] : nullptr;
239 }
240 return nullptr;
241 }
242
243 /*! To get a typeface
244 * \param styleIndex the index a font style set
245 * \param style the font style to be matching
246 * \param isFallback false, the font style set is generic
247 * \n true, the font style set is fallback
248 * \return An object of typeface whose font style is the closest matching to 'style'
249 * \n Return null, if 'styleIndex' is out of range
250 */
getTypeface(size_t styleIndex,const SkFontStyle & style,bool isFallback) const251 SkTypeface_OHOS* FontConfig_OHOS::getTypeface(size_t styleIndex, const SkFontStyle& style, bool isFallback) const
252 {
253 auto& fontSet = fFontCollection.getSet(isFallback);
254 if (styleIndex >= fontSet.size()) {
255 return nullptr;
256 }
257
258 const std::vector<sk_sp<SkTypeface_OHOS>>& pSet = fontSet[styleIndex].typefaces;
259 sk_sp<SkTypeface_OHOS> tp = matchFontStyle(pSet, style);
260 return tp.get();
261 }
262
263 /*! To get the index of a font style set
264 * \param familyName the family name of the font style set
265 * \n get the index of default font style set, if 'familyName' is null
266 * \param[out] isFallback to tell if the family is from generic or fallback to the caller.
267 * \n isFallback is false, if the font style is from generic family list
268 * \n isFallback is true, if the font style is from fallback family list
269 * \param[out] index the index of the font set
270 * \return The index of the font style set
271 * \n Return false, if 'familyName' is not found in the system
272 */
getStyleIndex(const char * familyName,bool & isFallback,size_t & index) const273 bool FontConfig_OHOS::getStyleIndex(const char* familyName, bool& isFallback, size_t& index) const
274 {
275 if (familyName == nullptr) {
276 isFallback = false;
277 return true;
278 }
279
280 std::lock_guard<std::mutex> lock(fFontMutex);
281 std::pair<size_t, FontType> res;
282 if (fFontCollection.getIndexByFamilyName(familyName, res)) {
283 isFallback = res.second == FontType::Fallback;
284 index = res.first;
285 return true;
286 }
287 return false;
288 }
289
290 /*! Find the closest matching typeface
291 * \param typefaceSet a typeface set belonging to the same font style set
292 * \param pattern the font style to be matching
293 * \return The typeface object which is the closest matching to 'pattern'
294 * \n Return null, if the count of typeface is 0
295 */
matchFontStyle(const std::vector<sk_sp<SkTypeface_OHOS>> & typefaceSet,const SkFontStyle & pattern)296 sk_sp<SkTypeface_OHOS> FontConfig_OHOS::matchFontStyle(
297 const std::vector<sk_sp<SkTypeface_OHOS>>& typefaceSet, const SkFontStyle& pattern)
298 {
299 int count = typefaceSet.size();
300 if (count == 1) {
301 return typefaceSet[0];
302 }
303 sk_sp<SkTypeface_OHOS> res = nullptr;
304 uint32_t minDiff = 0xFFFFFFFF;
305 for (int i = 0; i < count; i++) {
306 const SkFontStyle& fontStyle = typefaceSet[i]->fontStyle();
307 uint32_t diff = getFontStyleDifference(pattern, fontStyle);
308 if (diff < minDiff) {
309 minDiff = diff;
310 res = typefaceSet[i];
311 }
312 }
313 return res;
314 }
315
316 /*! To get the difference between a font style and the matching font style
317 * \param dstStyle the style to be matching
318 * \param srcStyle a font style
319 * \return The difference value of a specified style with the matching style
320 */
getFontStyleDifference(const SkFontStyle & dstStyle,const SkFontStyle & srcStyle)321 uint32_t FontConfig_OHOS::getFontStyleDifference(const SkFontStyle& dstStyle,
322 const SkFontStyle& srcStyle)
323 {
324 int normalWidth = SkFontStyle::kNormal_Width;
325 int dstWidth = dstStyle.width();
326 int srcWidth = srcStyle.width();
327
328 uint32_t widthDiff = 0;
329 // The maximum font width is kUltraExpanded_Width i.e. '9'.
330 // If dstWidth <= kNormal_Width (5), first check narrower values, then wider values.
331 // If dstWidth > kNormal_Width, first check wider values, then narrower values.
332 // When dstWidth and srcWidth are at different side of kNormal_Width,
333 // the width difference between them should be more than 5 (9/2+1)
334 constexpr int kWidthDiffThreshold = 9 / 2 + 1;
335 if (dstWidth <= normalWidth) {
336 widthDiff = (srcWidth <= dstWidth) ? (dstWidth - srcWidth)
337 : (srcWidth - dstWidth + kWidthDiffThreshold);
338 } else {
339 widthDiff = (srcWidth >= dstWidth) ? (srcWidth - dstWidth)
340 : (dstWidth - srcWidth + kWidthDiffThreshold);
341 }
342
343 constexpr int SLANT_RANGE = 3;
344 int diffSlantValue[SLANT_RANGE][SLANT_RANGE] = {
345 {0, 2, 1},
346 {2, 0, 1},
347 {2, 1, 0}
348 };
349 if (dstStyle.slant() < 0 || dstStyle.slant() >= SLANT_RANGE ||
350 srcStyle.slant() < 0 || srcStyle.slant() >= SLANT_RANGE) {
351 return 0;
352 }
353 uint32_t slantDiff = diffSlantValue[dstStyle.slant()][srcStyle.slant()];
354
355 int dstWeight = dstStyle.weight();
356 int srcWeight = srcStyle.weight();
357 uint32_t weightDiff = 0;
358
359 // The maximum weight is kExtraBlack_Weight (1000), when dstWeight and srcWeight are at the different
360 // side of kNormal_Weight, the weight difference between them should be more than 500 (1000/2)
361 constexpr int kWeightDiffThreshold = 1000 / 2;
362 if ((dstWeight == SkFontStyle::kNormal_Weight && srcWeight == SkFontStyle::kMedium_Weight) ||
363 (dstWeight == SkFontStyle::kMedium_Weight && srcWeight == SkFontStyle::kNormal_Weight)) {
364 weightDiff = 50;
365 } else if (dstWeight <= SkFontStyle::kNormal_Weight) {
366 weightDiff = (srcWeight <= dstWeight) ? (dstWeight - srcWeight)
367 : (srcWeight - dstWeight + kWeightDiffThreshold);
368 } else if (dstWeight > SkFontStyle::kNormal_Weight) {
369 weightDiff = (srcWeight >= dstWeight) ? (srcWeight - dstWeight)
370 : (dstWeight - srcWeight + kWeightDiffThreshold);
371 }
372 // The first 2 bytes to save weight difference, the third byte to save slant difference,
373 // and the fourth byte to save width difference
374 uint32_t diff = (widthDiff << 24) + (slantDiff << 16) + weightDiff;
375 return diff;
376 }
377
parseConfig(const char * fname)378 int FontConfig_OHOS::parseConfig(const char* fname)
379 {
380 if (fname == nullptr) {
381 fname = OHOS_DEFAULT_CONFIG;
382 }
383 Json::Value root;
384 int err = checkConfigFile(fname, root);
385 if (err != NO_ERROR) {
386 return err;
387 }
388
389 for (const auto& key : root.getMemberNames()) {
390 if (root[key].isArray() && key == "font_dir") {
391 parseFontDir(fname, root[key]);
392 } else if (root[key].isArray() && key == "fonts") {
393 parseFonts(root[key]);
394 }
395 }
396
397 return NO_ERROR;
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
411 /*! parse the font item from the json document
412 * \param array the font array from the json document
413 * \return NO_ERROR successful
414 */
parseFonts(const Json::Value & array)415 int FontConfig_OHOS::parseFonts(const Json::Value& array)
416 {
417 const std::unordered_map<std::string, std::function<void(FontConfig_OHOS::FontJson&, const Json::Value&)>>
418 funcMap = { { "type", GEN_GET_FONT_FUNC(f, type) }, { "family", GEN_GET_FONT_FUNC(f, family) },
419 { "index", GEN_GET_FONT_FUNC(f, index) }, { "weight", GEN_GET_FONT_FUNC(f, weight) },
420 { "lang", GEN_GET_FONT_FUNC(f, lang) }, { "file", GEN_GET_FONT_FUNC(f, file) },
421 { "alias", GEN_GET_FONT_FUNC(f, alias) } };
422
423 std::vector<FontJson> fonts;
424
425 for (const auto& font : array) {
426 if (!font.isObject()) {
427 continue;
428 }
429
430 FontJson f;
431 for (const auto& key : font.getMemberNames()) {
432 if (funcMap.count(key)) {
433 funcMap.at(key)(f, font[key]);
434 }
435 }
436
437 sk_sp<SkTypeface_OHOS> typeface = nullptr;
438 for (auto& dir : fFontDir) {
439 std::string path = dir + f.file;
440 std::array<uint32_t, 4> range{};
441 if (loadFont(path.c_str(), f, typeface, range) == 0) {
442 fFontCollection.emplaceFont(std::move(f), std::move(typeface), range);
443 break;
444 }
445 }
446 }
447 forAll([this](Font& f) { sortTypefaceSet(f.typefaces); });
448 return NO_ERROR;
449 }
450
451 /*! check the system font configuration document
452 * \param fname the full name of the font configuration document
453 * \return NO_ERROR successful
454 * \return ERROR_CONFIG_NOT_FOUND config document is not found
455 * \return ERROR_CONFIG_FORMAT_NOT_SUPPORTED config document format is not supported
456 */
checkConfigFile(const char * fname,Json::Value & root)457 int FontConfig_OHOS::checkConfigFile(const char* fname, Json::Value& root)
458 {
459 std::ifstream fstream(fname);
460
461 if (!fstream.is_open()) {
462 return ERROR_CONFIG_NOT_FOUND;
463 }
464
465 Json::Reader reader;
466 bool isJson = reader.parse(fstream, root, false);
467 if (!isJson) {
468 return ERROR_CONFIG_FORMAT_NOT_SUPPORTED;
469 }
470 return NO_ERROR;
471 }
472
473 /*! To parse 'fontdir' attribute
474 * \param root the root node of 'fontdir'
475 * \return NO_ERROR successful
476 */
parseFontDir(const char * fname,const Json::Value & root)477 int FontConfig_OHOS::parseFontDir(const char* fname, const Json::Value& root)
478 {
479 for (auto& path : root) {
480 if (!path.isString()) {
481 continue;
482 }
483 std::string dir;
484 #ifdef SK_BUILD_FONT_MGR_FOR_PREVIEW
485 if (strcmp(fname, OHOS_DEFAULT_CONFIG) == 0) {
486 dir = (path.asString() != "/system/fonts/") ? path.asString() : "fonts/";
487 } else {
488 dir = (path.asString() != "/system/fonts/")
489 ? path.asString() : "../../../../hms/previewer/resources/fonts/";
490 }
491 #else
492 dir = path.asString();
493 #endif
494 fFontDir.push_back(std::move(dir));
495 }
496 return NO_ERROR;
497 }
498
499 /*! To load font information from a font file
500 * \param fname the full name of a font file
501 * \param info the font information read from json document
502 * \param typeface the typeface to be loaded
503 * \return NO_ERROR successful
504 * \return ERROR_FONT_NOT_EXIST font file is not exist
505 * \return ERROR_FONT_INVALID_STREAM the stream is not recognized
506 */
loadFont(const char * fname,FontJson & info,sk_sp<SkTypeface_OHOS> & typeface,std::array<uint32_t,4> & range)507 int FontConfig_OHOS::loadFont(
508 const char* fname, FontJson& info, sk_sp<SkTypeface_OHOS>& typeface, std::array<uint32_t, 4>& range)
509 {
510 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(fname);
511 if (stream == nullptr) {
512 return ERROR_FONT_NOT_EXIST;
513 }
514 FontInfo font(fname, info.index);
515 SkTypeface_FreeType::Scanner::FontInfo fontInfo{ info.index, font.familyName, font.style, font.isFixedWidth };
516 if (!fFontScanner.scanFont(stream.get(), fontInfo, range)) {
517 return ERROR_FONT_INVALID_STREAM;
518 }
519
520 const char* temp = (info.type == FontType::Generic) ? info.alias.c_str() : "";
521 SkString family(temp);
522 typeface = sk_make_sp<SkTypeface_OHOS>(family, font);
523 return NO_ERROR;
524 }
525
loadHMSymbol()526 void FontConfig_OHOS::loadHMSymbol()
527 {
528 if (!G_IS_HMSYMBOL_ENABLE) {
529 return;
530 }
531 for (auto& dir : fFontDir) {
532 if (HmSymbolConfig_OHOS::GetInstance()->ParseConfigOfHmSymbol(
533 "hm_symbol_config_next.json", SkString(dir.c_str())) == NO_ERROR) {
534 return;
535 }
536 }
537 }
538
539 /*! To sort the typeface set
540 * \param typefaceSet the typeface set to be sorted
541 */
sortTypefaceSet(std::vector<sk_sp<SkTypeface_OHOS>> & typefaceSet)542 void FontConfig_OHOS::sortTypefaceSet(std::vector<sk_sp<SkTypeface_OHOS>>& typefaceSet)
543 {
544 std::sort(typefaceSet.begin(), typefaceSet.end(), [](const auto& a, const auto& b) {
545 return (a->fontStyle().weight() < b->fontStyle().weight()) ||
546 (a->fontStyle().weight() == b->fontStyle().weight() && a->fontStyle().slant() < b->fontStyle().slant());
547 });
548 }
549
550
judgeFileExist()551 bool FontConfig_OHOS::judgeFileExist()
552 {
553 bool haveFile = false;
554 for (const auto& path : fFontDir) {
555 DIR* dir = opendir(path.c_str());
556 if (dir == nullptr) {
557 continue;
558 }
559 struct dirent* node = nullptr;
560 #if defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_WIN)
561 struct stat fileStat;
562 #endif
563 while ((node = readdir(dir))) {
564 #if defined(SK_BUILD_FONT_MGR_FOR_PREVIEW_WIN)
565 stat(node->d_name, &fileStat);
566 if (S_ISDIR(fileStat.st_mode)) {
567 continue;
568 }
569 #else
570 if (node->d_type != DT_REG) {
571 continue;
572 }
573 #endif
574 const char* fileName = node->d_name;
575 int len = strlen(fileName);
576 int suffixLen = strlen(".ttf");
577 if (len < suffixLen ||
578 (strncmp(fileName + len - suffixLen, ".ttf", suffixLen) != 0 &&
579 strncmp(fileName + len - suffixLen, ".otf", suffixLen) != 0 &&
580 strncmp(fileName + len - suffixLen, ".ttc", suffixLen) != 0 &&
581 strncmp(fileName + len - suffixLen, ".otc", suffixLen) != 0)) {
582 continue;
583 }
584 haveFile = true;
585 break;
586 }
587 (void)closedir(dir);
588 if (haveFile) {
589 break;
590 }
591 }
592 return haveFile;
593 }
594
checkProductFile(const char * fname)595 int FontConfig_OHOS::checkProductFile(const char* fname)
596 {
597 std::lock_guard<std::mutex> lock(fFontMutex);
598 int err = parseConfig(PRODUCT_DEFAULT_CONFIG);
599 if (err != NO_ERROR || !judgeFileExist()) {
600 err = parseConfig(OHOS_DEFAULT_CONFIG);
601 }
602 return err;
603 }
604
605 static const std::map<std::pair<uint32_t, uint32_t>, int8_t> gRangeMap {
606 { { 0x0000, 0x007F }, 0 },
607 { { 0x0080, 0x00FF }, 1 },
608 { { 0x0100, 0x017F }, 2 },
609 { { 0x0180, 0x024F }, 3 },
610 { { 0x0250, 0x02AF }, 4 },
611 { { 0x1D00, 0x1DBF }, 4 },
612 { { 0x02B0, 0x02FF }, 5 },
613 { { 0xA700, 0xA71F }, 5 },
614 { { 0x0300, 0x036F }, 6 },
615 { { 0x1DC0, 0x1DFF }, 6 },
616 { { 0x0370, 0x03FF }, 7 },
617 { { 0x2C80, 0x2CFF }, 8 },
618 { { 0x0400, 0x052F }, 9 },
619 { { 0x2DE0, 0x2DFF }, 9 },
620 { { 0xA640, 0xA69F }, 9 },
621 { { 0x0530, 0x058F }, 10 },
622 { { 0x0590, 0x05FF }, 11 },
623 { { 0xA500, 0xA63F }, 12 },
624 { { 0x0600, 0x06FF }, 13 },
625 { { 0x0750, 0x077F }, 13 },
626 { { 0x07C0, 0x07FF }, 14 },
627 { { 0x0900, 0x097F }, 15 },
628 { { 0x0980, 0x09FF }, 16 },
629 { { 0x0A00, 0x0A7F }, 17 },
630 { { 0x0A80, 0x0AFF }, 18 },
631 { { 0x0B00, 0x0B7F }, 19 },
632 { { 0x0B80, 0x0BFF }, 20 },
633 { { 0x0C00, 0x0C7F }, 21 },
634 { { 0x0C80, 0x0CFF }, 22 },
635 { { 0x0D00, 0x0D7F }, 23 },
636 { { 0x0E00, 0x0E7F }, 24 },
637 { { 0x0E80, 0x0EFF }, 25 },
638 { { 0x10A0, 0x10FF }, 26 },
639 { { 0x2D00, 0x2D2F }, 26 },
640 { { 0x1B00, 0x1B7F }, 27 },
641 { { 0x1100, 0x11FF }, 28 },
642 { { 0x1E00, 0x1EFF }, 29 },
643 { { 0x2C60, 0x2C7F }, 29 },
644 { { 0xA720, 0xA7FF }, 29 },
645 { { 0x1F00, 0x1FFF }, 30 },
646 { { 0x2000, 0x206F }, 31 },
647 { { 0x2E00, 0x2E7F }, 31 },
648 { { 0x2070, 0x209F }, 32 },
649 { { 0x20A0, 0x20CF }, 33 },
650 { { 0x20D0, 0x20FF }, 34 },
651 { { 0x2100, 0x214F }, 35 },
652 { { 0x2150, 0x218F }, 36 },
653 { { 0x2190, 0x21FF }, 37 },
654 { { 0x27F0, 0x27FF }, 37 },
655 { { 0x2900, 0x297F }, 37 },
656 { { 0x2B00, 0x2BFF }, 37 },
657 { { 0x2200, 0x22FF }, 38 },
658 { { 0x2A00, 0x2AFF }, 38 },
659 { { 0x27C0, 0x27EF }, 38 },
660 { { 0x2980, 0x29FF }, 38 },
661 { { 0x2300, 0x23FF }, 39 },
662 { { 0x2400, 0x243F }, 40 },
663 { { 0x2440, 0x245F }, 41 },
664 { { 0x2460, 0x24FF }, 42 },
665 { { 0x2500, 0x257F }, 43 },
666 { { 0x2580, 0x259F }, 44 },
667 { { 0x25A0, 0x25FF }, 45 },
668 { { 0x2600, 0x26FF }, 46 },
669 { { 0x2700, 0x27BF }, 47 },
670 { { 0x3000, 0x303F }, 48 },
671 { { 0x3040, 0x309F }, 49 },
672 { { 0x30A0, 0x30FF }, 50 },
673 { { 0x31F0, 0x31FF }, 50 },
674 { { 0x3100, 0x312F }, 51 },
675 { { 0x31A0, 0x31BF }, 51 },
676 { { 0x3130, 0x318F }, 52 },
677 { { 0xA840, 0xA87F }, 53 },
678 { { 0x3200, 0x32FF }, 54 },
679 { { 0x3300, 0x33FF }, 55 },
680 { { 0xAC00, 0xD7AF }, 56 },
681 // Ignore Non-Plane 0 (57), since this is not a real range.
682 { { 0x10900, 0x1091F }, 58 },
683 { { 0x4E00, 0x9FFF }, 59 },
684 { { 0x2E80, 0x2FDF }, 59 },
685 { { 0x2FF0, 0x2FFF }, 59 },
686 { { 0x3400, 0x4DBF }, 59 },
687 { { 0x20000, 0x2A6DF }, 59 },
688 { { 0x3190, 0x319F }, 59 },
689 { { 0xE000, 0xF8FF }, 60 },
690 { { 0x31C0, 0x31EF }, 61 },
691 { { 0xF900, 0xFAFF }, 61 },
692 { { 0x2F800, 0x2FA1F }, 61 },
693 { { 0xFB00, 0xFB4F }, 62 },
694 { { 0xFB50, 0xFDFF }, 63 },
695 { { 0xFE20, 0xFE2F }, 64 },
696 { { 0xFE10, 0xFE1F }, 65 },
697 { { 0xFE30, 0xFE4F }, 65 },
698 { { 0xFE50, 0xFE6F }, 66 },
699 { { 0xFE70, 0xFEFF }, 67 },
700 { { 0xFF00, 0xFFEF }, 68 },
701 { { 0xFFF0, 0xFFFF }, 69 },
702 { { 0x0F00, 0x0FFF }, 70 },
703 { { 0x0700, 0x074F }, 71 },
704 { { 0x0780, 0x07BF }, 72 },
705 { { 0x0D80, 0x0DFF }, 73 },
706 { { 0x1000, 0x109F }, 74 },
707 { { 0x1200, 0x139F }, 75 },
708 { { 0x2D80, 0x2DDF }, 75 },
709 { { 0x13A0, 0x13FF }, 76 },
710 { { 0x1400, 0x167F }, 77 },
711 { { 0x1680, 0x169F }, 78 },
712 { { 0x16A0, 0x16FF }, 79 },
713 { { 0x1780, 0x17FF }, 80 },
714 { { 0x19E0, 0x19FF }, 80 },
715 { { 0x1800, 0x18AF }, 81 },
716 { { 0x2800, 0x28FF }, 82 },
717 { { 0xA000, 0xA48F }, 83 },
718 { { 0xA490, 0xA4CF }, 83 },
719 { { 0x1700, 0x177F }, 84 },
720 { { 0x10300, 0x1032F }, 85 },
721 { { 0x10330, 0x1034F }, 86 },
722 { { 0x10400, 0x1044F }, 87 },
723 { { 0x1D000, 0x1D24F }, 88 },
724 { { 0x1D400, 0x1D7FF }, 89 },
725 { { 0xF0000, 0xFFFFD }, 90 },
726 { { 0x100000, 0x10FFFD }, 90 },
727 { { 0xFE00, 0xFE0F }, 91 },
728 { { 0xE0100, 0xE01EF }, 91 },
729 { { 0xE0000, 0xE007F }, 92 },
730 { { 0x1900, 0x194F }, 93 },
731 { { 0x1950, 0x197F }, 94 },
732 { { 0x1980, 0x19DF }, 95 },
733 { { 0x1A00, 0x1A1F }, 96 },
734 { { 0x2C00, 0x2C5F }, 97 },
735 { { 0x2D30, 0x2D7F }, 98 },
736 { { 0x4DC0, 0x4DFF }, 99 },
737 { { 0xA800, 0xA82F }, 100 },
738 { { 0x10000, 0x1013F }, 101 },
739 { { 0x10140, 0x1018F }, 102 },
740 { { 0x10380, 0x1039F }, 103 },
741 { { 0x103A0, 0x103DF }, 104 },
742 { { 0x10450, 0x1047F }, 105 },
743 { { 0x10480, 0x104AF }, 106 },
744 { { 0x10800, 0x1083F }, 107 },
745 { { 0x10A00, 0x10A5F }, 108 },
746 { { 0x1D300, 0x1D35F }, 109 },
747 { { 0x12000, 0x123FF }, 110 },
748 { { 0x12400, 0x1247F }, 110 },
749 { { 0x1D360, 0x1D37F }, 111 },
750 { { 0x1B80, 0x1BBF }, 112 },
751 { { 0x1C00, 0x1C4F }, 113 },
752 { { 0x1C50, 0x1C7F }, 114 },
753 { { 0xA880, 0xA8DF }, 115 },
754 { { 0xA900, 0xA92F }, 116 },
755 { { 0xA930, 0xA95F }, 117 },
756 { { 0xAA00, 0xAA5F }, 118 },
757 { { 0x10190, 0x101CF }, 119 },
758 { { 0x101D0, 0x101FF }, 120 },
759 { { 0x102A0, 0x102DF }, 121 },
760 { { 0x10280, 0x1029F }, 121 },
761 { { 0x10920, 0x1093F }, 121 },
762 { { 0x1F030, 0x1F09F }, 122 },
763 { { 0x1F000, 0x1F02F }, 122 },
764 };
765
charRangeIndex(SkUnichar unicode)766 static int8_t charRangeIndex(SkUnichar unicode)
767 {
768 auto it = gRangeMap.upper_bound({ unicode, INT32_MAX });
769 if (it != gRangeMap.begin()) {
770 --it;
771 }
772 if (unicode >= it->first.first && unicode <= it->first.second) {
773 return it->second;
774 }
775 return -1;
776 }
777
containChar(SkUnichar unicode) const778 bool FontConfig_OHOS::Font::containChar(SkUnichar unicode) const
779 {
780 int8_t r = charRangeIndex(unicode);
781 if (r < 0) {
782 return false;
783 }
784 // because the range is 128-bit, so we need to split it into 4 32-bit, / 32 means >> 5
785 int8_t i = r >> 5;
786 // get the bit position by mod 32 which means & 31
787 int8_t bit = r & 31;
788 return ((range[i] >> bit) & 1) != 0;
789 }