• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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