• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2021 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 data
342  * \param fontData the given font data used to create a typeface
343  * \return The object of typeface, if successful
344  * \n      Return null if the typeface cannot be created from the font data.
345  * \note The caller must call unref() on the returned object if it's not null
346  */
onMakeFromFontData(std::unique_ptr<SkFontData> data) const347 sk_sp<SkTypeface> SkFontMgr_OHOS::onMakeFromFontData(std::unique_ptr<SkFontData> data) const
348 {
349     if (fontConfig == nullptr) {
350         return nullptr;
351     }
352     if (data == nullptr || !data->hasStream()) {
353         LOGE("%s\n", FontConfig_OHOS::errToString(ERROR_FONT_NO_STREAM));
354         return nullptr;
355     }
356 
357     return makeTypeface(data.get());
358 }
359 
360 /*! To create a typeface from the specified font file and TTC index
361  * \param path the full path of the given font file
362  * \param ttcIndex the index of typeface in a ttc font file. 0 means none.
363  * \return The object of typeface, if successful
364  * \n      Return null if the font file is not found or the content of file is not recognized.
365  * \note The caller must call unref() on the returned object if it's not null
366  */
onMakeFromFile(const char path[],int ttcIndex) const367 sk_sp<SkTypeface> SkFontMgr_OHOS::onMakeFromFile(const char path[], int ttcIndex) const
368 {
369     if (fontConfig == nullptr) {
370         return nullptr;
371     }
372 
373     std::unique_ptr<SkStreamAsset> stream = SkStreamAsset::MakeFromFile(path);
374     if (stream == nullptr) {
375         LOGE("%s : %s\n", FontConfig_OHOS::errToString(ERROR_FONT_NOT_EXIST), path);
376         return nullptr;
377     }
378     SkFontArguments args;
379     args.setCollectionIndex(ttcIndex);
380     return this->makeTypeface(std::move(stream), args, path);
381 }
382 
383 /*! To get a typeface matching the specified family and style
384  * \param familyName the specified name to be matching
385  * \param style the specified style to be matching
386  * \return The object of typeface which is the closest matching 'style' when the familyName is found
387  * \return Return a typeface from the default family, if familyName is not found
388  * \return Return null, if there is no any typeface in the system
389  * \note The caller must caller unref() on the returned object is it's not null
390  */
onLegacyMakeTypeface(const char familyName[],SkFontStyle style) const391 sk_sp<SkTypeface> SkFontMgr_OHOS::onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const
392 {
393     SkTypeface* typeface = this->onMatchFamilyStyle(familyName, style);
394     // if familyName is not found, then try the default family
395     if (typeface == nullptr && familyName != nullptr) {
396         typeface = this->onMatchFamilyStyle(nullptr, style);
397     }
398 
399     if (typeface) {
400         return sk_sp<SkTypeface>(typeface);
401     }
402     LOGE("%s\n", FontConfig_OHOS::errToString(ERROR_NO_AVAILABLE_FAMILY));
403     return nullptr;
404 }
405 
406 /*! To make a typeface from the specified stream and font arguments
407  * \param stream the specified stream to be parsed to get font information
408  * \param args the arguments of index or axis values
409  * \param path the fullname of font file
410  * \return The object of typeface if successful
411  * \n      Return null, if the stream is not recognized
412  */
makeTypeface(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args,const char path[]) const413 sk_sp<SkTypeface> SkFontMgr_OHOS::makeTypeface(std::unique_ptr<SkStreamAsset> stream,
414     const SkFontArguments& args, const char path[]) const
415 {
416     FontInfo fontInfo;
417     int ttcIndex = args.getCollectionIndex();
418     int axisCount = args.getVariationDesignPosition().coordinateCount;
419 
420     if (path) {
421         fontInfo.fname.set(path);
422     }
423     if (axisCount == 0) {
424         if (!fontScanner.scanFont(stream.get(), ttcIndex, &fontInfo.familyName, &fontInfo.style,
425             &fontInfo.isFixedWidth, nullptr)) {
426             LOGE("%s\n", FontConfig_OHOS::errToString(ERROR_FONT_INVALID_STREAM));
427             return nullptr;
428         }
429     } else {
430         AxisDefinitions axisDef;
431         if (!fontScanner.scanFont(stream.get(), ttcIndex, &fontInfo.familyName, &fontInfo.style,
432             &fontInfo.isFixedWidth, &axisDef)) {
433             LOGE("%s\n", FontConfig_OHOS::errToString(ERROR_FONT_INVALID_STREAM));
434             return nullptr;
435         }
436         if (axisDef.count() > 0) {
437             SkFixed axis[axisCount];
438             fontScanner.computeAxisValues(axisDef, args.getVariationDesignPosition(),
439                 axis, fontInfo.familyName);
440             fontInfo.setAxisSet(axisCount, axis, axisDef.data());
441         }
442     }
443 
444     fontInfo.stream = std::move(stream);
445     fontInfo.index = ttcIndex;
446     return sk_make_sp<SkTypeface_OHOS>(fontInfo);
447 }
448 
449 /*! To make a typeface from the specified font data
450  * \param fontData the given font data used to create a typeface
451  * \return The object of typeface, if successful
452  * \n      Return null, if the font data is not recognized
453  */
makeTypeface(SkFontData * fontData) const454 sk_sp<SkTypeface> SkFontMgr_OHOS::makeTypeface(SkFontData* fontData) const
455 {
456     FontInfo fontInfo;
457     int ttcIndex = fontData->getIndex();
458     int axisCount = fontData->getAxisCount();
459     SkStreamAsset* stream = fontData->getStream();
460     if (axisCount == 0) {
461         if (!fontScanner.scanFont(stream, ttcIndex, &fontInfo.familyName, &fontInfo.style,
462             &fontInfo.isFixedWidth, nullptr)) {
463             LOGE("%s\n", FontConfig_OHOS::errToString(ERROR_FONT_INVALID_STREAM));
464             return nullptr;
465         }
466     } else {
467         const SkFixed* axis = fontData->getAxis();
468         AxisDefinitions axisDefs;
469         if (!fontScanner.scanFont(stream, ttcIndex, &fontInfo.familyName, &fontInfo.style,
470             &fontInfo.isFixedWidth, &axisDefs)) {
471             LOGE("%s\n", FontConfig_OHOS::errToString(ERROR_FONT_INVALID_STREAM));
472             return nullptr;
473         }
474         if (axisDefs.count() > 0) {
475             fontInfo.setAxisSet(axisCount, axis, axisDefs.data());
476         }
477     }
478 
479     fontInfo.stream = fontData->detachStream();
480     fontInfo.index = ttcIndex;
481     return sk_make_sp<SkTypeface_OHOS>(fontInfo);
482 }
483 
484 /*! To create SkFontMgr object for Harmony platform
485  * \param fname the full name of system font configuration documents
486  * \return The object of SkFontMgr_OHOS
487  */
SkFontMgr_New_OHOS(const char * fname)488 sk_sp<SkFontMgr> SkFontMgr_New_OHOS(const char* fname)
489 {
490     return sk_make_sp<SkFontMgr_OHOS>(fname);
491 }
492