• 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 
5 #include "SkFontMgr_ohos.h"
6 
7 #include <string>
8 
9 #include "SkTypeface_ohos.h"
10 #include "include/core/SkData.h"
11 
12 using namespace ErrorCode;
13 
14 /*! Constructor
15  * \param path the full path of system font configuration document
16  */
SkFontMgr_OHOS(const char * path)17 SkFontMgr_OHOS::SkFontMgr_OHOS(const char* path)
18 {
19     fFontConfig = std::make_shared<FontConfig_OHOS>(fFontScanner, path);
20     fFamilyCount = fFontConfig->getFamilyCount();
21 }
22 
23 /*! To get the count of families
24  * \return The count of families in the system
25  */
onCountFamilies() const26 int SkFontMgr_OHOS::onCountFamilies() const
27 {
28     return fFamilyCount;
29 }
30 
31 /*! To get the family name for a font style set
32  * \param index the index of a font style set
33  * \param[out] familyName the family name returned to the caller
34  * \n          The family name will be reset to "", if index is out of range
35  */
onGetFamilyName(int index,SkString * familyName) const36 void SkFontMgr_OHOS::onGetFamilyName(int index, SkString* familyName) const
37 {
38     if (fFontConfig == nullptr || familyName == nullptr) {
39         return;
40     }
41     fFontConfig->getFamilyName(static_cast<size_t>(index), *familyName);
42 }
43 
44 /*! To create an object of SkFontStyleSet
45  * \param index the index of a font style set
46  * \return The pointer of SkFontStyleSet
47  * \n      Return null, if index is out of range
48  * \note   The caller must call unref() on the returned object if it's not null
49  */
onCreateStyleSet(int index) const50 SkFontStyleSet* SkFontMgr_OHOS::onCreateStyleSet(int index) const
51 {
52     if (fFontConfig == nullptr) {
53         return nullptr;
54     }
55     if (index < 0 || index >= this->countFamilies()) {
56         return nullptr;
57     }
58     return new SkFontStyleSet_OHOS(fFontConfig, index);
59 }
60 
61 /*! To get a matched object of SkFontStyleSet
62  * \param familyName the family name of a font style set
63  * \return The pointer of SkFontStyleSet
64  * \n      Return the default font style set, if family name is null
65  * \n      Return null, if family name is not found
66  * \note   The caller must call unref() on the returned object if it's not null
67  */
onMatchFamily(const char familyName[]) const68 SkFontStyleSet* SkFontMgr_OHOS::onMatchFamily(const char familyName[]) const
69 {
70     if (fFontConfig == nullptr) {
71         return nullptr;
72     }
73     // return default system font when familyName is null
74     if (familyName == nullptr) {
75         return new SkFontStyleSet_OHOS(fFontConfig, 0);
76     }
77 
78     bool isFallback = false;
79     size_t index = 0;
80     if (!fFontConfig->getStyleIndex(familyName, isFallback, index)) {
81         return nullptr;
82     }
83     return new SkFontStyleSet_OHOS(fFontConfig, index, isFallback);
84 }
85 
86 /*! To get a matched typeface
87  * \param familyName the family name of a font style set
88  * \param style the font style to be matched
89  * \return An object of typeface which is closest matching to 'style'
90  * \n      Return the typeface in the default font style set, if family name is null
91  * \n      Return null, if family name is not found
92  * \note   The caller must call unref() on the returned object if it's not null
93  */
onMatchFamilyStyle(const char familyName[],const SkFontStyle & style) const94 SkTypeface* SkFontMgr_OHOS::onMatchFamilyStyle(const char familyName[], const SkFontStyle& style) const
95 {
96     if (fFontConfig == nullptr) {
97         return nullptr;
98     }
99     bool isFallback = false;
100     size_t styleIndex = 0;
101     if (!fFontConfig->getStyleIndex(familyName, isFallback, styleIndex)) {
102         return nullptr;
103     }
104     return SkSafeRef(fFontConfig->getTypeface(styleIndex, style, isFallback));
105 }
106 
107 struct SpecialUnicodeFamilyName {
108     SkUnichar unicode;
109     std::string familyName;
110 };
111 
findSpecialTypeface(SkUnichar character,const SkFontStyle & style) const112 SkTypeface* SkFontMgr_OHOS::findSpecialTypeface(SkUnichar character, const SkFontStyle& style) const
113 {
114     // The key values in this list are Unicode that support the identification characters
115     // of several high-frequency languages in the fallback list corresponding to Chinese, Uyghur, and Tibetan
116     static std::vector<SpecialUnicodeFamilyName> specialLists = {
117         {0x0626, "HarmonyOS Sans Naskh Arabic UI"},
118         {0x0F56, "Noto Serif Tibetan"}
119     };
120 
121     std::string name;
122 
123     // base chinese unicode range is 0x4E00-0x9FA5
124     if (character >= 0x4E00 && character <= 0x9FA5) {
125         name.assign("HarmonyOS Sans SC");
126     }
127 
128     for (int i = 0; i < specialLists.size() && name.empty(); i++) {
129         if (character == specialLists[i].unicode) {
130             name.assign(specialLists[i].familyName);
131             break;
132         }
133     }
134 
135     if (name.empty()) {
136         return nullptr;
137     }
138 
139     SkString fname(name.c_str());
140     sk_sp<SkTypeface_OHOS> typeface = fFontConfig->getFallbackTypeface(fname, style);
141     return SkSafeRef(typeface.get());
142 }
143 
144 /*! To get a matched typeface
145  * \n Use the system fallback to find a typeface for the given character.
146  * \param familyName the family name which the typeface is fallback For
147  * \param style the font style to be matched
148  * \param bcp47 an array of languages which indicate the language of 'character'
149  * \param bcp47Count the array size of bcp47
150  * \param character a UTF8 value to be matched
151  * \return An object of typeface which is for the given character
152  * \return Return the typeface in the default fallback set, if familyName is null
153  * \return Return null, if the typeface is not found for the given character
154  * \note The caller must call unref() on the returned object if it's not null
155  */
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const156 SkTypeface* SkFontMgr_OHOS::onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle& style,
157     const char* bcp47[], int bcp47Count, SkUnichar character) const
158 {
159     if (fFontConfig == nullptr) {
160         return nullptr;
161     }
162 
163     auto res = findTypeface(style, bcp47, bcp47Count, character);
164     if (res != nullptr) {
165         return res;
166     }
167     res = findSpecialTypeface(character, style);
168     if (res != nullptr) {
169         return res;
170     }
171     return fFontConfig->matchFallback(character, style);
172 }
173 
174 /*! To find the matched typeface for the given parameters
175  * \n Use the system fallback to find a typeface for the given character.
176  * \param fallbackItem the fallback items in which to find the typeface
177  * \param style the font style to be matched
178  * \param bcp47 an array of languages which indicate the language of 'character'
179  * \param bcp47Count the array size of bcp47
180  * \param character a UTF8 value to be matched
181  * \return An object of typeface which is for the given character
182  * \return Return null, if the typeface is not found for the given character
183  */
findTypeface(const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const184 SkTypeface* SkFontMgr_OHOS::findTypeface(const SkFontStyle& style,
185     const char* bcp47[], int bcp47Count, SkUnichar character) const
186 {
187     if (bcp47Count == 0 || fFontConfig == nullptr) {
188         return nullptr;
189     }
190 
191     std::vector<std::function<int(const std::string& langs)>> funcs = {
192         [&bcp47, &bcp47Count](const std::string& langs) -> int {
193             for (int i = 0; i < bcp47Count; i++) {
194                 if (langs == bcp47[i]) {
195                     return i;
196                 }
197             }
198             return -1;
199         },
200         [&bcp47, &bcp47Count](const std::string& langs) -> int {
201             return SkFontMgr_OHOS::compareLangs(langs, bcp47, bcp47Count);
202         }
203     };
204 
205     for (auto& func : funcs) {
206         auto set = fFontConfig->matchFallbackByBCP47(func);
207         for (auto& index : set) {
208             auto res = fFontConfig->matchFallback(index, character, style);
209             if (res != nullptr) {
210                 return res;
211             }
212         }
213     }
214 
215     return nullptr;
216 }
217 
218 /*! To compare the languages of an typeface with a bcp47 list
219  * \param langs the supported languages by an typeface
220  * \param bcp47 the array of bcp47 language to be matching
221  * \param bcp47Count the array size of bcp47
222  * \return The index of language in bcp47, if matching happens
223  * \n      Return -1, if no language matching happens
224  */
compareLangs(const std::string & langs,const char * bcp47[],int bcp47Count)225 int SkFontMgr_OHOS::compareLangs(const std::string& langs, const char* bcp47[], int bcp47Count)
226 {
227     /*
228      * zh-Hans : ('zh' : iso639 code, 'Hans' : iso15924 code)
229      */
230     if (bcp47 == nullptr || bcp47Count == 0) {
231         return -1;
232     }
233     for (int i = bcp47Count - 1; i >= 0; i--) {
234         if (langs.find(bcp47[i]) != -1) {
235             return i;
236         } else {
237             const char* iso15924 = strrchr(bcp47[i], '-');
238             if (iso15924 == nullptr) {
239                 continue;
240             }
241             iso15924++;
242             int len = iso15924 - 1 - bcp47[i];
243             SkString country(bcp47[i], len);
244             if (langs.find(iso15924) != std::string::npos ||
245                 (strncmp(bcp47[i], "und", strlen("und")) != 0 && langs.find(country.c_str()) != -1)) {
246                 return i + bcp47Count;
247             }
248         }
249     }
250     return -1;
251 }
252 
253 /*! To get a matched typeface
254  * \param typeface the given typeface with which the returned object should be in the same style set
255  * \param style the font style to be matching
256  * \return The object of typeface which is closest matching to the given 'style'
257  * \n      Return null, if the family name of the given typeface is not found in the system
258  * \note The caller must call unref() on the returned object if it's not null
259  */
onMatchFaceStyle(const SkTypeface * typeface,const SkFontStyle & style) const260 SkTypeface* SkFontMgr_OHOS::onMatchFaceStyle(const SkTypeface* typeface, const SkFontStyle& style) const
261 {
262     if (typeface == nullptr) {
263         return nullptr;
264     }
265     SkString familyName;
266     typeface->getFamilyName(&familyName);
267     return this->onMatchFamilyStyle(familyName.c_str(), style);
268 }
269 
270 /*! To create a typeface from the specified data and TTC index
271  * \param data the data to be parsed
272  * \param index the index of typeface. 0 for none
273  * \return The object of typeface, if successful
274  * \n      Return null if the data is not recognized.
275  * \note The caller must call unref() on the returned object if it's not null
276  */
onMakeFromData(sk_sp<SkData> data,int ttcIndex) const277 sk_sp<SkTypeface> SkFontMgr_OHOS::onMakeFromData(sk_sp<SkData> data, int ttcIndex) const
278 {
279     if (data == nullptr) {
280         return nullptr;
281     }
282     std::unique_ptr<SkMemoryStream> memoryStream = std::make_unique<SkMemoryStream>(data);
283     SkFontArguments args;
284     args.setCollectionIndex(ttcIndex);
285     return this->makeTypeface(std::move(memoryStream), args, nullptr);
286 }
287 
288 /*! To create a typeface from the specified stream and TTC index
289  * \param data the stream to be parsed
290  * \param index the index of typeface. 0 for none
291  * \return The object of typeface, if successful
292  * \n      Return null if the stream is not recognized.
293  * \note The caller must call unref() on the returned object if it's not null
294  */
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,int ttcIndex) const295 sk_sp<SkTypeface> SkFontMgr_OHOS::onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
296     int ttcIndex) const
297 {
298     if (stream == nullptr) {
299         return nullptr;
300     }
301     SkFontArguments args;
302     args.setCollectionIndex(ttcIndex);
303     return this->makeTypeface(std::move(stream), args, nullptr);
304 }
305 
306 /*! To create a typeface from the specified stream and font arguments
307  * \param data the stream to be parsed
308  * \param args the arguments of font
309  * \return The object of typeface, if successful
310  * \n      Return null if the stream is not recognized.
311  * \note The caller must call unref() on the returned object if it's not null
312  */
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args) const313 sk_sp<SkTypeface> SkFontMgr_OHOS::onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,
314     const SkFontArguments& args) const
315 {
316     if (stream == nullptr) {
317         return nullptr;
318     }
319 
320     return this->makeTypeface(std::move(stream), args, nullptr);
321 }
322 
323 /*! To create a typeface from the specified font file and TTC index
324  * \param path the full path of the given font file
325  * \param ttcIndex the index of typeface in a ttc font file. 0 means none.
326  * \return The object of typeface, if successful
327  * \n      Return null if the font file is not found or the content of file is not recognized.
328  * \note The caller must call unref() on the returned object if it's not null
329  */
onMakeFromFile(const char path[],int ttcIndex) const330 sk_sp<SkTypeface> SkFontMgr_OHOS::onMakeFromFile(const char path[], int ttcIndex) const
331 {
332     if (fFontConfig == nullptr) {
333         return nullptr;
334     }
335 
336     std::unique_ptr<SkStreamAsset> stream = SkStreamAsset::MakeFromFile(path);
337     if (stream == nullptr) {
338         return nullptr;
339     }
340     SkFontArguments args;
341     args.setCollectionIndex(ttcIndex);
342     return this->makeTypeface(std::move(stream), args, path);
343 }
344 
345 /*! To get a typeface matching the specified family and style
346  * \param familyName the specified name to be matching
347  * \param style the specified style to be matching
348  * \return The object of typeface which is the closest matching 'style' when the familyName is found
349  * \return Return a typeface from the default family, if familyName is not found
350  * \return Return null, if there is no any typeface in the system
351  * \note The caller must caller unref() on the returned object is it's not null
352  */
onLegacyMakeTypeface(const char familyName[],SkFontStyle style) const353 sk_sp<SkTypeface> SkFontMgr_OHOS::onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const
354 {
355     SkTypeface* typeface = this->onMatchFamilyStyle(familyName, style);
356     // if familyName is not found, then try the default family
357     if (typeface == nullptr && familyName != nullptr) {
358         typeface = this->onMatchFamilyStyle(nullptr, style);
359     }
360 
361     if (typeface) {
362         return sk_sp<SkTypeface>(typeface);
363     }
364     return nullptr;
365 }
366 
367 #ifdef OHOS_SUPPORT
onGetSystemFonts() const368 std::vector<sk_sp<SkTypeface>> SkFontMgr_OHOS::onGetSystemFonts() const
369 {
370     if (fFontConfig == nullptr) {
371         return {};
372     }
373     std::vector<sk_sp<SkTypeface>> skTypefaces;
374     fFontConfig->forAll([&skTypefaces](const auto& f) {
375         for (auto& iter : f.typefaces) {
376             skTypefaces.emplace_back(iter);
377         }
378     });
379 
380     return skTypefaces;
381 }
382 #endif
383 
384 /*! To make a typeface from the specified stream and font arguments
385  * \param stream the specified stream to be parsed to get font information
386  * \param args the arguments of index or axis values
387  * \param path the fullname of font file
388  * \return The object of typeface if successful
389  * \n      Return null, if the stream is not recognized
390  */
makeTypeface(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args,const char path[]) const391 sk_sp<SkTypeface> SkFontMgr_OHOS::makeTypeface(std::unique_ptr<SkStreamAsset> stream,
392     const SkFontArguments& args, const char path[]) const
393 {
394     FontInfo fontInfo;
395     int ttcIndex = args.getCollectionIndex();
396     int axisCount = args.getVariationDesignPosition().coordinateCount;
397 
398     if (path) {
399         fontInfo.fname.set(path);
400     }
401     if (axisCount == 0) {
402         if (!fFontScanner.scanFont(stream.get(), ttcIndex, &fontInfo.familyName,
403                                    &fontInfo.style, &fontInfo.isFixedWidth, nullptr)) {
404             return nullptr;
405         }
406     } else {
407         SkTypeface_FreeType::Scanner::AxisDefinitions axisDef;
408         if (!fFontScanner.scanFont(stream.get(), ttcIndex, &fontInfo.familyName,
409                                    &fontInfo.style, &fontInfo.isFixedWidth, &axisDef)) {
410             return nullptr;
411         }
412         if (axisDef.count() > 0) {
413             SkFixed axis[axisDef.count()];
414             SkTypeface_FreeType::Scanner::computeAxisValues(
415                 axisDef, args.getVariationDesignPosition(), axis, fontInfo.familyName);
416             fontInfo.setAxisSet(axisCount, axis, axisDef.data());
417             fontInfo.style = fontInfo.computeFontStyle();
418         }
419     }
420 
421     fontInfo.stream = std::move(stream);
422     fontInfo.index = ttcIndex;
423     return sk_make_sp<SkTypeface_OHOS>(fontInfo);
424 }
425 
426 /*! Get the fullname of font
427  * \param fontFd      The file descriptor for the font file
428  * \param fullnameVec Read the font fullname list
429  * \return Returns Whether the fullnameVec was successfully obtained, 0 means success, see FontCheckCode for details
430  */
GetFontFullName(int fontFd,std::vector<SkByteArray> & fullnameVec)431 int SkFontMgr_OHOS::GetFontFullName(int fontFd, std::vector<SkByteArray> &fullnameVec)
432 {
433     std::unique_ptr<SkMemoryStream> stream = std::make_unique<SkMemoryStream>(SkData::MakeFromFD(fontFd));
434     int errorCode = SUCCESSED;
435     int numFaces = 0;
436     if (!fFontScanner.recognizedFont(stream.get(), &numFaces)) {
437         return ERROR_TYPE_OTHER;
438     }
439     for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
440         bool isFixedPitch = false;
441         SkString realname;
442         SkFontStyle style = SkFontStyle(); // avoid uninitialized warning
443         if (!fFontScanner.scanFont(stream.get(), faceIndex, &realname, &style, &isFixedPitch, nullptr)) {
444             errorCode = ERROR_TYPE_OTHER;
445             break;
446         }
447         SkByteArray skFullName = {nullptr, 0};
448         if (!fFontScanner.GetTypefaceFullname(stream.get(), faceIndex, skFullName)) {
449             errorCode = ERROR_TYPE_OTHER;
450             break;
451         } else {
452             fullnameVec.push_back(std::move(skFullName));
453         }
454     }
455     return errorCode;
456 }
457 
458 /*! To create SkFontMgr object for Harmony platform
459  * \param fname the full name of system font configuration documents
460  * \return The object of SkFontMgr_OHOS
461  */
SkFontMgr_New_OHOS(const char * fname)462 sk_sp<SkFontMgr> SkFontMgr_New_OHOS(const char* fname)
463 {
464     return sk_make_sp<SkFontMgr_OHOS>(fname);
465 }
466