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