1 // Copyright (c) 2023 Huawei Device Co., Ltd. All rights reserved
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 #ifdef ENABLE_TEXT_ENHANCE
5 #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 sk_sp<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 sk_sp<SkFontStyleSet>(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 sk_sp<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 sk_sp<SkFontStyleSet>(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 sk_sp<SkFontStyleSet>(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 sk_sp<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 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 sk_sp<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 typeface;
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 sk_sp<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 sk_sp<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 sk_sp<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 sk_sp<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 typeface;
363 }
364 return nullptr;
365 }
366
onGetSystemFonts() const367 std::vector<sk_sp<SkTypeface>> SkFontMgr_OHOS::onGetSystemFonts() const
368 {
369 if (fFontConfig == nullptr) {
370 return {};
371 }
372 std::vector<sk_sp<SkTypeface>> skTypefaces;
373 SkString familyName;
374 fFontConfig->forAll([&skTypefaces, &familyName](const auto& f) {
375 for (const auto& iter : f.typefaces) {
376 if (iter == nullptr || iter->getFontInfo() == nullptr) {
377 continue;
378 }
379 iter->getFamilyName(&familyName);
380 skTypefaces.emplace_back(sk_make_sp<SkTypeface_OHOS>(familyName, *iter->getFontInfo()));
381 }
382 });
383
384 return skTypefaces;
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 (!fFontScanner.scanFont(stream.get(), ttcIndex, &fontInfo.familyName,
406 &fontInfo.style, &fontInfo.isFixedWidth, nullptr)) {
407 return nullptr;
408 }
409 } else {
410 SkFontScanner_FreeType::AxisDefinitions axisDef;
411 if (!fFontScanner.scanFont(stream.get(), ttcIndex, &fontInfo.familyName,
412 &fontInfo.style, &fontInfo.isFixedWidth, &axisDef)) {
413 return nullptr;
414 }
415 if (axisDef.size() > 0) {
416 SkFixed axis[axisDef.size()];
417 SkFontScanner_FreeType::computeAxisValues(
418 axisDef,
419 SkFontArguments::VariationPosition{nullptr, 0},
420 args.getVariationDesignPosition(),
421 axis, fontInfo.familyName, nullptr);
422 fontInfo.setAxisSet(axisCount, axis, axisDef.data());
423 fontInfo.style = fontInfo.computeFontStyle();
424 }
425 }
426
427 fontInfo.stream = std::move(stream);
428 fontInfo.index = ttcIndex;
429 return sk_make_sp<SkTypeface_OHOS>(fontInfo);
430 }
431
432 /*! Get the fullname of font
433 * \param fontFd The file descriptor for the font file
434 * \param fullnameVec Read the font fullname list
435 * \return Returns Whether the fullnameVec was successfully obtained, 0 means success, see FontCheckCode for details
436 */
GetFontFullName(int fontFd,std::vector<SkByteArray> & fullnameVec)437 int SkFontMgr_OHOS::GetFontFullName(int fontFd, std::vector<SkByteArray> &fullnameVec)
438 {
439 std::unique_ptr<SkMemoryStream> stream = std::make_unique<SkMemoryStream>(SkData::MakeFromFD(fontFd));
440 int errorCode = SUCCESSED;
441 int numFaces = 0;
442 if (!fFontScanner.scanFile(stream.get(), &numFaces)) {
443 return ERROR_TYPE_OTHER;
444 }
445 for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
446 bool isFixedPitch = false;
447 SkString realname;
448 SkFontStyle style = SkFontStyle(); // avoid uninitialized warning
449 if (!fFontScanner.scanFont(stream.get(), faceIndex, &realname, &style, &isFixedPitch, nullptr)) {
450 errorCode = ERROR_TYPE_OTHER;
451 break;
452 }
453 SkByteArray skFullName = {nullptr, 0};
454 if (!fFontScanner.GetTypefaceFullname(stream.get(), faceIndex, skFullName)) {
455 errorCode = ERROR_TYPE_OTHER;
456 break;
457 } else {
458 fullnameVec.push_back(std::move(skFullName));
459 }
460 }
461 return errorCode;
462 }
463
464 /*! To create SkFontMgr object for Harmony platform
465 * \param fname the full name of system font configuration documents
466 * \return The object of SkFontMgr_OHOS
467 */
SkFontMgr_New_OHOS(const char * fname)468 sk_sp<SkFontMgr> SkFontMgr_New_OHOS(const char* fname)
469 {
470 return sk_make_sp<SkFontMgr_OHOS>(fname);
471 }
472
473 #endif // ENABLE_TEXT_ENHANCE