• 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 "SkTypeface_ohos.h"
8 
9 using namespace ErrorCode;
10 
11 /*! Constructor
12  * \param path the full path of system font configuration document
13  */
SkFontMgr_OHOS(const char * path)14 SkFontMgr_OHOS::SkFontMgr_OHOS(const char* path)
15 {
16     fontConfig = std::make_shared<FontConfig_OHOS>(fontScanner, path);
17     familyCount = fontConfig->getFamilyCount();
18 }
19 
20 /*! To get the count of families
21  * \return The count of families in the system
22  */
onCountFamilies() const23 int SkFontMgr_OHOS::onCountFamilies() const
24 {
25     return familyCount;
26 }
27 
28 /*! To get the family name for a font style set
29  * \param index the index of a font style set
30  * \param[out] familyName the family name returned to the caller
31  * \n          The family name will be reset to "", if index is out of range
32  */
onGetFamilyName(int index,SkString * familyName) const33 void SkFontMgr_OHOS::onGetFamilyName(int index, SkString* familyName) const
34 {
35     if (fontConfig == nullptr || familyName == nullptr) {
36         return;
37     }
38     fontConfig->getFamilyName(index, familyName);
39 }
40 
41 /*! To create an object of SkFontStyleSet
42  * \param index the index of a font style set
43  * \return The pointer of SkFontStyleSet
44  * \n      Return null, if index is out of range
45  * \note   The caller must call unref() on the returned object if it's not null
46  */
onCreateStyleSet(int index) const47 SkFontStyleSet* SkFontMgr_OHOS::onCreateStyleSet(int index) const
48 {
49     if (fontConfig == nullptr) {
50         return nullptr;
51     }
52     if (index < 0 || index >= this->countFamilies()) {
53         return nullptr;
54     }
55     return new SkFontStyleSet_OHOS(fontConfig, index);
56 }
57 
58 /*! To get a matched object of SkFontStyleSet
59  * \param familyName the family name of a font style set
60  * \return The pointer of SkFontStyleSet
61  * \n      Return the default font style set, if family name is null
62  * \n      Return null, if family name is not found
63  * \note   The caller must call unref() on the returned object if it's not null
64  */
onMatchFamily(const char familyName[]) const65 SkFontStyleSet* SkFontMgr_OHOS::onMatchFamily(const char familyName[]) const
66 {
67     if (fontConfig == nullptr) {
68         return nullptr;
69     }
70     // return default system font when familyName is null
71     if (familyName == nullptr) {
72         return new SkFontStyleSet_OHOS(fontConfig, 0);
73     }
74 
75     bool isFallback = false;
76     int index = fontConfig->getStyleIndex(familyName, isFallback);
77     if (index == -1) {
78         return nullptr;
79     }
80     return new SkFontStyleSet_OHOS(fontConfig, index, isFallback);
81 }
82 
83 /*! To get a matched typeface
84  * \param familyName the family name of a font style set
85  * \param style the font style to be matched
86  * \return An object of typeface which is closest matching to 'style'
87  * \n      Return the typeface in the default font style set, if family name is null
88  * \n      Return null, if family name is not found
89  * \note   The caller must call unref() on the returned object if it's not null
90  */
onMatchFamilyStyle(const char familyName[],const SkFontStyle & style) const91 SkTypeface* SkFontMgr_OHOS::onMatchFamilyStyle(const char familyName[], const SkFontStyle& style) const
92 {
93     if (fontConfig == nullptr) {
94         return nullptr;
95     }
96     bool isFallback = false;
97     int styleIndex = 0;
98     if (familyName) {
99         styleIndex = fontConfig->getStyleIndex(familyName, isFallback);
100     }
101     return SkSafeRef(fontConfig->getTypeface(styleIndex, style, isFallback));
102 }
103 
104 /*! To get a matched typeface
105  * \n Use the system fallback to find a typeface for the given character.
106  * \param familyName the family name which the typeface is fallback For
107  * \param style the font style to be matched
108  * \param bcp47 an array of languages which indicate the language of 'character'
109  * \param bcp47Count the array size of bcp47
110  * \param character a UTF8 value to be matched
111  * \return An object of typeface which is for the given character
112  * \return Return the typeface in the default fallback set, if familyName is null
113  * \return Return null, if the typeface is not found for the given character
114  * \note The caller must call unref() on the returned object if it's not null
115  */
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const116 SkTypeface* SkFontMgr_OHOS::onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle& style,
117     const char* bcp47[], int bcp47Count, SkUnichar character) const
118 {
119     if (fontConfig == nullptr) {
120         return nullptr;
121     }
122     const FallbackForMap& fallbackForMap = fontConfig->getFallbackForMap();
123     const FallbackSet& fallbackSet = fontConfig->getFallbackSet();
124     SkString defaultFamily("");
125     SkString key = defaultFamily;
126     FallbackSetPos* item = nullptr;
127     if (familyName == nullptr) {
128         item = fallbackForMap.find(defaultFamily);
129     } else {
130         item = fallbackForMap.find(SkString(familyName));
131         if (item) {
132             key = SkString(familyName);
133         } else {
134             item = fallbackForMap.find(defaultFamily);
135         }
136     }
137     if (item == nullptr) {
138         LOGE("%s : '%s' must be a fallback key in the config file\n",
139             FontConfig_OHOS::errToString(ERROR_FAMILY_NOT_FOUND), defaultFamily.c_str());
140         return nullptr;
141     }
142     while (true) {
143         if (bcp47Count > 0) {
144             SkTypeface* retTp = findTypeface(*item, style, bcp47, bcp47Count, character);
145             if (retTp) {
146                 return retTp;
147             }
148             if (key == defaultFamily) {
149                 bcp47Count = 0;
150                 continue;
151             }
152             item = fallbackForMap.find(defaultFamily);
153             key = defaultFamily;
154         } else {
155             for (unsigned int i = item->index; i < item->index + item->count && i < fallbackSet.size(); i++) {
156                 const TypefaceSet& tpSet = *(fallbackSet[i]->typefaceSet.get());
157                 if (tpSet.size() > 0 && tpSet[0]->unicharToGlyph(character) != 0) {
158                     sk_sp<SkTypeface> typeface = FontConfig_OHOS::matchFontStyle(tpSet, style);
159                     return SkSafeRef(typeface.get());
160                 }
161             }
162             if (key == defaultFamily) {
163                 break;
164             }
165             item = fallbackForMap.find(defaultFamily);
166             key = defaultFamily;
167         }
168     }
169     return nullptr;
170 }
171 
172 /*! To find the matched typeface for the given parameters
173  * \n Use the system fallback to find a typeface for the given character.
174  * \param fallbackItem the fallback items in which to find the typeface
175  * \param style the font style to be matched
176  * \param bcp47 an array of languages which indicate the language of 'character'
177  * \param bcp47Count the array size of bcp47
178  * \param character a UTF8 value to be matched
179  * \return An object of typeface which is for the given character
180  * \return Return null, if the typeface is not found for the given character
181  */
findTypeface(const FallbackSetPos & fallbackItem,const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const182 SkTypeface* SkFontMgr_OHOS::findTypeface(const FallbackSetPos& fallbackItem, const SkFontStyle& style,
183     const char* bcp47[], int bcp47Count, SkUnichar character) const
184 {
185     if (bcp47Count == 0) {
186         return nullptr;
187     }
188 
189     const FallbackSet& fallbackSet = fontConfig->getFallbackSet();
190     // example bcp47 code : 'zh-Hans' : ('zh' : iso639 code, 'Hans' : iso15924 code)
191     // iso639 code will be taken from bcp47 code, so that we can try to match
192     // bcp47 or only iso639. Therefore totalCount need to be 'bcp47Count * 2'
193     int totalCount = bcp47Count * 2;
194     int tps[totalCount];
195     for (int i = 0; i < totalCount; i++) {
196         tps[i] = -1;
197     }
198     // find the families matching the bcp47 list
199     for (unsigned int i = fallbackItem.index; i < fallbackItem.index + fallbackItem.count
200         && i < fallbackSet.size(); i++) {
201         int ret = compareLangs(fallbackSet[i]->langs, bcp47, bcp47Count, tps);
202         if (ret == -1) {
203             continue;
204         }
205         tps[ret] = i;
206     }
207     // match typeface in families
208     for (int i = bcp47Count - 1; i >= 0; i--) {
209         if (tps[i] == -1) {
210             continue;
211         }
212         const TypefaceSet& tpSet = *(fallbackSet[tps[i]]->typefaceSet.get());
213         if (tpSet.size() > 0 && tpSet[0]->unicharToGlyph(character) != 0) {
214             sk_sp<SkTypeface> typeface = FontConfig_OHOS::matchFontStyle(tpSet, style);
215             return SkSafeRef(typeface.get());
216         }
217     }
218     for (int i = totalCount - 1; i >= bcp47Count; i--) {
219         if (tps[i] == -1) {
220             continue;
221         }
222         const TypefaceSet& tpSet = *(fallbackSet[tps[i]]->typefaceSet.get());
223         if (tpSet.size() > 0 && tpSet[0]->unicharToGlyph(character) != 0) {
224             sk_sp<SkTypeface> typeface = FontConfig_OHOS::matchFontStyle(tpSet, style);
225             return SkSafeRef(typeface.get());
226         }
227     }
228     return nullptr;
229 }
230 
231 /*! To compare the languages of an typeface with a bcp47 list
232  * \param langs the supported languages by an typeface
233  * \param bcp47 the array of bcp47 language to be matching
234  * \param bcp47Count the array size of bcp47
235  * \param tps an array of the index of typeface which is matching one value of bcp47
236  * \return The index of language in bcp47, if matching happens
237  * \n      Return -1, if no language matching happens
238  */
compareLangs(const SkString & langs,const char * bcp47[],int bcp47Count,const int tps[]) const239 int SkFontMgr_OHOS::compareLangs(const SkString& langs, const char* bcp47[],
240     int bcp47Count, const int tps[]) const
241 {
242     /*
243      * zh-Hans : ('zh' : iso639 code, 'Hans' : iso15924 code)
244      */
245     if (bcp47 == nullptr || bcp47Count == 0) {
246         return -1;
247     }
248     for (int i = bcp47Count - 1; i >= 0; i--) {
249         if (tps[i] != -1) {
250             continue;
251         }
252         if (langs.find(bcp47[i]) != -1) {
253             return i;
254         } else {
255             const char* iso15924 = strrchr(bcp47[i], '-');
256             if (iso15924 == nullptr) {
257                 continue;
258             }
259             iso15924++;
260             int len = iso15924 - 1 - bcp47[i];
261             SkString country(bcp47[i], len);
262             if (langs.find(iso15924) != -1 ||
263                 (strncmp(bcp47[i], "und", strlen("und")) && langs.find(country.c_str()) != -1)) {
264                 return i + bcp47Count;
265             }
266         }
267     }
268     return -1;
269 }
270 
271 /*! To get a matched typeface
272  * \param typeface the given typeface with which the returned object should be in the same style set
273  * \param style the font style to be matching
274  * \return The object of typeface which is closest matching to the given 'style'
275  * \n      Return null, if the family name of the given typeface is not found in the system
276  * \note The caller must call unref() on the returned object if it's not null
277  */
onMatchFaceStyle(const SkTypeface * typeface,const SkFontStyle & style) const278 SkTypeface* SkFontMgr_OHOS::onMatchFaceStyle(const SkTypeface* typeface, const SkFontStyle& style) const
279 {
280     if (typeface == nullptr) {
281         return nullptr;
282     }
283     SkString familyName;
284     typeface->getFamilyName(&familyName);
285     return this->onMatchFamilyStyle(familyName.c_str(), style);
286 }
287 
288 /*! To create a typeface from the specified data and TTC index
289  * \param data the data 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 data is not recognized.
293  * \note The caller must call unref() on the returned object if it's not null
294  */
onMakeFromData(sk_sp<SkData> data,int ttcIndex) const295 sk_sp<SkTypeface> SkFontMgr_OHOS::onMakeFromData(sk_sp<SkData> data, int ttcIndex) const
296 {
297     if (data == nullptr) {
298         return nullptr;
299     }
300     std::unique_ptr<SkMemoryStream> memoryStream = std::make_unique<SkMemoryStream>(data);
301     SkFontArguments args;
302     args.setCollectionIndex(ttcIndex);
303     return this->makeTypeface(std::move(memoryStream), args, nullptr);
304 }
305 
306 /*! To create a typeface from the specified stream and TTC index
307  * \param data the stream to be parsed
308  * \param index the index of typeface. 0 for none
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  */
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,int ttcIndex) const313 sk_sp<SkTypeface> SkFontMgr_OHOS::onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
314     int ttcIndex) const
315 {
316     if (stream == nullptr) {
317         return nullptr;
318     }
319     SkFontArguments args;
320     args.setCollectionIndex(ttcIndex);
321     return this->makeTypeface(std::move(stream), args, nullptr);
322 }
323 
324 /*! To create a typeface from the specified stream and font arguments
325  * \param data the stream to be parsed
326  * \param args the arguments of font
327  * \return The object of typeface, if successful
328  * \n      Return null if the stream is not recognized.
329  * \note The caller must call unref() on the returned object if it's not null
330  */
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args) const331 sk_sp<SkTypeface> SkFontMgr_OHOS::onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,
332     const SkFontArguments& args) const
333 {
334     if (stream == nullptr) {
335         return nullptr;
336     }
337 
338     return this->makeTypeface(std::move(stream), args, nullptr);
339 }
340 
341 /*! To create a typeface from the specified font file and TTC index
342  * \param path the full path of the given font file
343  * \param ttcIndex the index of typeface in a ttc font file. 0 means none.
344  * \return The object of typeface, if successful
345  * \n      Return null if the font file is not found or the content of file is not recognized.
346  * \note The caller must call unref() on the returned object if it's not null
347  */
onMakeFromFile(const char path[],int ttcIndex) const348 sk_sp<SkTypeface> SkFontMgr_OHOS::onMakeFromFile(const char path[], int ttcIndex) const
349 {
350     if (fontConfig == nullptr) {
351         return nullptr;
352     }
353 
354     std::unique_ptr<SkStreamAsset> stream = SkStreamAsset::MakeFromFile(path);
355     if (stream == nullptr) {
356         LOGE("%s : %s\n", FontConfig_OHOS::errToString(ERROR_FONT_NOT_EXIST), path);
357         return nullptr;
358     }
359     SkFontArguments args;
360     args.setCollectionIndex(ttcIndex);
361     return this->makeTypeface(std::move(stream), args, path);
362 }
363 
364 /*! To get a typeface matching the specified family and style
365  * \param familyName the specified name to be matching
366  * \param style the specified style to be matching
367  * \return The object of typeface which is the closest matching 'style' when the familyName is found
368  * \return Return a typeface from the default family, if familyName is not found
369  * \return Return null, if there is no any typeface in the system
370  * \note The caller must caller unref() on the returned object is it's not null
371  */
onLegacyMakeTypeface(const char familyName[],SkFontStyle style) const372 sk_sp<SkTypeface> SkFontMgr_OHOS::onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const
373 {
374     SkTypeface* typeface = this->onMatchFamilyStyle(familyName, style);
375     // if familyName is not found, then try the default family
376     if (typeface == nullptr && familyName != nullptr) {
377         typeface = this->onMatchFamilyStyle(nullptr, style);
378     }
379 
380     if (typeface) {
381         return sk_sp<SkTypeface>(typeface);
382     }
383     LOGE("%s\n", FontConfig_OHOS::errToString(ERROR_NO_AVAILABLE_FAMILY));
384     return nullptr;
385 }
386 
387 /*! To make a typeface from the specified stream and font arguments
388  * \param stream the specified stream to be parsed to get font information
389  * \param args the arguments of index or axis values
390  * \param path the fullname of font file
391  * \return The object of typeface if successful
392  * \n      Return null, if the stream is not recognized
393  */
makeTypeface(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args,const char path[]) const394 sk_sp<SkTypeface> SkFontMgr_OHOS::makeTypeface(std::unique_ptr<SkStreamAsset> stream,
395     const SkFontArguments& args, const char path[]) const
396 {
397     FontInfo fontInfo;
398     int ttcIndex = args.getCollectionIndex();
399     int axisCount = args.getVariationDesignPosition().coordinateCount;
400 
401     if (path) {
402         fontInfo.fname.set(path);
403     }
404     if (axisCount == 0) {
405         if (!fontScanner.scanFont(stream.get(), ttcIndex, &fontInfo.familyName, &fontInfo.style,
406             &fontInfo.isFixedWidth, nullptr)) {
407             LOGE("%s\n", FontConfig_OHOS::errToString(ERROR_FONT_INVALID_STREAM));
408             return nullptr;
409         }
410     } else {
411         AxisDefinitions axisDef;
412         if (!fontScanner.scanFont(stream.get(), ttcIndex, &fontInfo.familyName, &fontInfo.style,
413             &fontInfo.isFixedWidth, &axisDef)) {
414             LOGE("%s\n", FontConfig_OHOS::errToString(ERROR_FONT_INVALID_STREAM));
415             return nullptr;
416         }
417         if (axisDef.count() > 0) {
418             SkFixed axis[axisCount];
419             fontScanner.computeAxisValues(axisDef, args.getVariationDesignPosition(),
420                 axis, fontInfo.familyName);
421             fontInfo.setAxisSet(axisCount, axis, axisDef.data());
422         }
423     }
424 
425     fontInfo.stream = std::move(stream);
426     fontInfo.index = ttcIndex;
427     return sk_make_sp<SkTypeface_OHOS>(fontInfo);
428 }
429 
430 /*! To create SkFontMgr object for Harmony platform
431  * \param fname the full name of system font configuration documents
432  * \return The object of SkFontMgr_OHOS
433  */
SkFontMgr_New_OHOS(const char * fname)434 sk_sp<SkFontMgr> SkFontMgr_New_OHOS(const char* fname)
435 {
436     return sk_make_sp<SkFontMgr_OHOS>(fname);
437 }
438