1 /*
2 * Copyright (c) 2020-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "font/ui_font_vector.h"
17
18 #include <freetype/ftbitmap.h>
19 #include <freetype/ftoutln.h>
20 #include <freetype/internal/ftobjs.h>
21 #include <freetype/internal/ftstream.h>
22 #include <freetype/tttags.h>
23
24 #include "common/typed_text.h"
25 #include "draw/draw_utils.h"
26 #include "font/font_ram_allocator.h"
27 #include "gfx_utils/file.h"
28 #include "gfx_utils/graphic_log.h"
29 #include "graphic_config.h"
30 #include "securec.h"
31 #if defined(ENABLE_MULTI_FONT) && ENABLE_MULTI_FONT
32 #include "font/ui_multi_font_manager.h"
33 #endif
34 #if defined(ENABLE_SHAPING) && ENABLE_SHAPING
35 #include "font/ui_text_shaping.h"
36 #endif
37 #include "font/ui_font_cache_manager.h"
38
39 namespace OHOS {
UIFontVector()40 UIFontVector::UIFontVector()
41 {
42 #ifdef _WIN32
43 ttfDir_ = _pgmptr;
44 size_t len = ttfDir_.size();
45 size_t pos = ttfDir_.find_last_of('\\');
46 if (pos != std::string::npos) {
47 ttfDir_.replace((pos + 1), (len - pos), VECTOR_FONT_DIR);
48 }
49 #else
50 ttfDir_ = VECTOR_FONT_DIR;
51 #endif // _WIN32
52 ftLibrary_ = nullptr;
53 freeTypeInited_ = ((FT_Init_FreeType(&ftLibrary_) == 0) ? true : false);
54 }
55
~UIFontVector()56 UIFontVector::~UIFontVector()
57 {
58 if (freeTypeInited_) {
59 FT_Done_FreeType(ftLibrary_);
60 freeTypeInited_ = false;
61 UnregisterFontInfo(DEFAULT_VECTOR_FONT_FILENAME);
62 }
63 }
64
IsColorEmojiFont(FT_Face & face)65 bool UIFontVector::IsColorEmojiFont(FT_Face& face)
66 {
67 static const uint32_t tag = FT_MAKE_TAG('C', 'B', 'D', 'T');
68 FT_ULong length = 0;
69 FT_Load_Sfnt_Table(face, tag, 0, nullptr, &length);
70 if (length) {
71 return true;
72 }
73 return false;
74 }
75
SetupColorFont(FT_Face face,uint8_t fontSize)76 int8_t SetupColorFont(FT_Face face, uint8_t fontSize)
77 {
78 if (face->num_fixed_sizes == 0) {
79 return INVALID_RET_VALUE;
80 }
81 FT_Int bestMatch = 0;
82 int32_t diff = MATH_ABS(fontSize - face->available_sizes[0].width);
83 for (int32_t i = 1; i < face->num_fixed_sizes; ++i) {
84 int32_t ndiff = MATH_ABS(fontSize - face->available_sizes[i].width);
85 if (ndiff < diff) {
86 bestMatch = i;
87 diff = ndiff;
88 }
89 }
90 return FT_Select_Size(face, bestMatch); // FT_Match_Size
91 }
92
RegisterFontInfo(const char * ttfName,uint8_t shaping)93 uint8_t UIFontVector::RegisterFontInfo(const char* ttfName, uint8_t shaping)
94 {
95 if ((ttfName == nullptr) || !freeTypeInited_) {
96 return FONT_INVALID_TTF_ID;
97 }
98
99 int32_t j = 0;
100 while (j < FONT_ID_MAX) {
101 if ((fontInfo_[j].ttfName != nullptr) && !strncmp(fontInfo_[j].ttfName, ttfName, TTF_NAME_LEN_MAX)) {
102 return j;
103 } else if (fontInfo_[j].ttfName == nullptr) {
104 std::string ttfPath = ttfDir_;
105 ttfPath.append(ttfName);
106 int32_t error = FT_New_Face(ftLibrary_, ttfPath.c_str(), 0, &ftFaces_[j]);
107 if (error != 0) {
108 return FONT_INVALID_TTF_ID;
109 }
110 fontInfo_[j].ttfName = ttfName;
111 fontInfo_[j].shaping = shaping;
112 fontInfo_[j].ttfId = j;
113 fontInfo_[j].ttcIndex = FONT_TTC_MAX;
114 currentFontInfoNum_ = j + 1;
115 if (IsColorEmojiFont(ftFaces_[j])) {
116 fontInfo_[j].fontWeight = BPP_BIT_32;
117 } else {
118 fontInfo_[j].fontWeight = BPP_BIT_8;
119 }
120 #if defined(ENABLE_MULTI_FONT) && ENABLE_MULTI_FONT
121 UIMultiFontManager::GetInstance()->UpdateScript(fontInfo_[j]);
122 #endif
123 return j;
124 }
125 j++;
126 }
127 return FONT_INVALID_TTF_ID;
128 }
129
RegisterFontInfo(const UITextLanguageFontParam * fontsTable,uint8_t num)130 uint8_t UIFontVector::RegisterFontInfo(const UITextLanguageFontParam* fontsTable, uint8_t num)
131 {
132 if (fontsTable == nullptr) {
133 return FONT_INVALID_TTF_ID;
134 }
135 uint8_t count = 0;
136 for (uint8_t i = 0; i < num; i++) {
137 uint8_t result = RegisterFontInfo(fontsTable[i].ttfName, fontsTable[i].shaping);
138 if (result == FONT_INVALID_TTF_ID) {
139 continue;
140 }
141 count++;
142 }
143 return count;
144 }
145
146 // Note: when use ttc font file, freetype should export FT_Stream_New/FT_Stream_Free function
RegisterTtcFontInfo(const char * ttcName,const TtfInfo * ttfInfo,uint8_t count)147 uint8_t UIFontVector::RegisterTtcFontInfo(const char* ttcName, const TtfInfo* ttfInfo, uint8_t count)
148 {
149 if ((ttcName == nullptr) || !freeTypeInited_) {
150 return FONT_INVALID_TTF_ID;
151 }
152
153 int32_t i = 0;
154 int32_t error = 0;
155 int32_t ttfIdx = 0;
156 while (i < FONT_TTC_MAX) {
157 if ((ttcInfos_[i].ttcName != nullptr) && !strncmp(ttcInfos_[i].ttcName, ttcName, TTF_NAME_LEN_MAX)) {
158 return i;
159 } else if (ttcInfos_[i].ttcName == nullptr) {
160 std::string ttcPath = ttfDir_;
161 ttcPath.append(ttcName);
162 FT_Open_Args args = {FT_OPEN_PATHNAME, nullptr, 0, const_cast<char*>(ttcPath.c_str()),
163 nullptr, nullptr, 0, nullptr};
164 error = FT_Stream_New(ftLibrary_, &args, &ttcInfos_[i].stream);
165 if (error != 0) {
166 return FONT_INVALID_TTF_ID;
167 }
168 ttcInfos_[i].ttcName = ttcName;
169 args = {FT_OPEN_STREAM, nullptr, 0, nullptr, ttcInfos_[i].stream, nullptr, 0, nullptr};
170 for (uint8_t j = 0; j < count; j++) {
171 while ((ttfIdx < FONT_ID_MAX) && fontInfo_[ttfIdx].ttfName != nullptr) {
172 ttfIdx++;
173 }
174
175 if (ttfIdx >= FONT_ID_MAX) {
176 return FONT_INVALID_TTF_ID;
177 }
178 error = FT_Open_Face(ftLibrary_, &args, j, &ftFaces_[ttfIdx]);
179 if (error != 0) {
180 continue;
181 }
182 fontInfo_[ttfIdx].ttfName = ttfInfo[j].ttfName;
183 fontInfo_[ttfIdx].shaping = ttfInfo[j].shaping;
184 fontInfo_[ttfIdx].ttfId = ttfIdx;
185 fontInfo_[ttfIdx].ttfIndex = j;
186 fontInfo_[ttfIdx].ttcIndex = i;
187 if (IsColorEmojiFont(ftFaces_[ttfIdx])) {
188 fontInfo_[ttfIdx].fontWeight = BPP_BIT_32;
189 } else {
190 fontInfo_[ttfIdx].fontWeight = BPP_BIT_8;
191 }
192 #if defined(ENABLE_MULTI_FONT) && ENABLE_MULTI_FONT
193 UIMultiFontManager::GetInstance()->UpdateScript(fontInfo_[ttfIdx]);
194 #endif
195 }
196 return i;
197 }
198 i++;
199 }
200 return FONT_INVALID_TTF_ID;
201 }
202
UnregisterTtcFontInfo(const char * ttcName,const TtfInfo * ttfInfo,uint8_t count)203 uint8_t UIFontVector::UnregisterTtcFontInfo(const char* ttcName, const TtfInfo* ttfInfo, uint8_t count)
204 {
205 if (ttcName == nullptr || ttfInfo == nullptr) {
206 return FONT_INVALID_TTF_ID;
207 }
208
209 uint8_t i = 0;
210 while (i < FONT_TTC_MAX) {
211 if ((ttcInfos_[i].ttcName != nullptr) && !strncmp(ttcInfos_[i].ttcName, ttcName, TTF_NAME_LEN_MAX)) {
212 for (uint8_t j = 0; j < count; j++) {
213 UnregisterFontInfo(ttfInfo[j].ttfName);
214 }
215 FT_Stream_Free(ttcInfos_[i].stream, 1);
216 ttcInfos_[i].ttcName = nullptr;
217 ttcInfos_[i].stream = nullptr;
218 return i;
219 }
220 i++;
221 }
222 return FONT_INVALID_TTF_ID;
223 }
224
UnregisterFontInfo(const UITextLanguageFontParam * fontsTable,uint8_t num)225 uint8_t UIFontVector::UnregisterFontInfo(const UITextLanguageFontParam* fontsTable, uint8_t num)
226 {
227 if (fontsTable == nullptr) {
228 return 0;
229 }
230 uint8_t count = 0;
231 for (uint8_t i = 0; i < num; i++) {
232 uint8_t result = UnregisterFontInfo(fontsTable[i].ttfName);
233 if (result == FONT_INVALID_TTF_ID) {
234 return FONT_INVALID_TTF_ID;
235 }
236 count++;
237 }
238 return count;
239 }
UnregisterFontInfo(const char * ttfName)240 uint8_t UIFontVector::UnregisterFontInfo(const char* ttfName)
241 {
242 if (ttfName != nullptr) {
243 int32_t i = 0;
244 while (i < FONT_ID_MAX) {
245 if ((fontInfo_[i].ttfName != nullptr) && !strncmp(fontInfo_[i].ttfName, ttfName, TTF_NAME_LEN_MAX)) {
246 fontInfo_[i].ttfName = nullptr;
247 FT_Done_Face(ftFaces_[i]);
248 ftFaces_[i] = nullptr;
249 fontSize_[i] = 0;
250 return static_cast<uint8_t>(i);
251 }
252 i++;
253 }
254 }
255 return FONT_INVALID_TTF_ID;
256 }
257
GetFontInfo(uint16_t fontId) const258 const UITextLanguageFontParam* UIFontVector::GetFontInfo(uint16_t fontId) const
259 {
260 if (fontId < FONT_ID_MAX) {
261 return static_cast<const UITextLanguageFontParam*>(&fontInfo_[fontId]);
262 }
263 return nullptr;
264 }
265
OpenVectorFont(uint8_t ttfId)266 int32_t UIFontVector::OpenVectorFont(uint8_t ttfId)
267 {
268 int32_t i = 0;
269 int32_t fp = 0;
270 while (i < FONT_ID_MAX) {
271 if (fontInfo_[i].ttfName == nullptr) {
272 i++;
273 continue;
274 }
275 if (fontInfo_[i].ttfId == ttfId) {
276 std::string ttfPath = ttfDir_;
277 ttfPath.append(fontInfo_[i].ttfName);
278 #ifdef _WIN32
279 fp = open(ttfPath.c_str(), O_RDONLY | O_BINARY);
280 #else
281 fp = open(ttfPath.c_str(), O_RDONLY);
282 #endif
283 return fp;
284 }
285 i++;
286 }
287 return -1;
288 }
GetTtfInfo(uint8_t ttfId,uint8_t * ttfBuffer,uint32_t ttfBufferSize,TtfHeader & ttfHeader)289 bool UIFontVector::GetTtfInfo(uint8_t ttfId, uint8_t* ttfBuffer, uint32_t ttfBufferSize, TtfHeader& ttfHeader)
290 {
291 if ((ttfBuffer == nullptr) || (ttfBufferSize == 0)) {
292 return false;
293 }
294 for (int16_t i = 0; i < FONT_ID_MAX; i++) {
295 if (fontInfo_[i].ttfName == nullptr) {
296 continue;
297 }
298 if (fontInfo_[i].ttfId == ttfId) {
299 if (fontInfo_[i].ttcIndex != FONT_TTC_MAX) {
300 return GetTtfInfoFromTtc(ttfBuffer, ttfBufferSize, ttfHeader, fontInfo_[i]);
301 } else {
302 return GetTtfInfoFromTtf(ttfBuffer, ttfBufferSize, ttfHeader, fontInfo_[i]);
303 }
304 }
305 }
306 return false;
307 }
308
GetTtfInfoFromTtf(uint8_t * ttfBuffer,uint32_t ttfBufferSize,TtfHeader & ttfHeader,UITextLanguageFontParam fontInfo)309 bool UIFontVector::GetTtfInfoFromTtf(uint8_t* ttfBuffer,
310 uint32_t ttfBufferSize,
311 TtfHeader& ttfHeader,
312 UITextLanguageFontParam fontInfo)
313 {
314 if ((ttfBuffer == nullptr) || (ttfBufferSize == 0)) {
315 return false;
316 }
317 std::string ttfPath = ttfDir_;
318 ttfPath.append(fontInfo.ttfName);
319 int32_t fpTtf = 0;
320 #ifdef _WIN32
321 fpTtf = open(ttfPath.c_str(), O_RDONLY | O_BINARY);
322 #else
323 fpTtf = open(ttfPath.c_str(), O_RDONLY);
324 #endif
325 if (fpTtf < 0) {
326 return false;
327 }
328 int32_t headerLength = lseek(fpTtf, 0, SEEK_END);
329 if (headerLength < 0) {
330 return false;
331 }
332 ttfHeader.len = static_cast<uint32_t>(headerLength);
333 if (ttfHeader.len > ttfBufferSize) {
334 close(fpTtf);
335 return false;
336 }
337 int32_t ret = lseek(fpTtf, 0, SEEK_SET);
338 if (ret != 0) {
339 close(fpTtf);
340 return false;
341 }
342 ret = read(fpTtf, reinterpret_cast<void*>(ttfBuffer), ttfHeader.len);
343 if (ret != headerLength) {
344 close(fpTtf);
345 return false;
346 }
347 close(fpTtf);
348 return true;
349 }
350
351 struct TtcHeader {
352 uint32_t ttcTag;
353 uint16_t major;
354 uint16_t minor;
355 int32_t numFonts;
356 };
GetTtfInfoFromTtc(uint8_t * ttfBuffer,uint32_t ttfBufferSize,TtfHeader & ttfHeader,UITextLanguageFontParam fontInfo)357 bool UIFontVector::GetTtfInfoFromTtc(uint8_t* ttfBuffer,
358 uint32_t ttfBufferSize,
359 TtfHeader& ttfHeader,
360 UITextLanguageFontParam fontInfo)
361 {
362 if ((ttfBuffer == nullptr) || (ttfBufferSize == 0) || (fontInfo.ttcIndex >= FONT_TTC_MAX)) {
363 return false;
364 }
365 FT_Stream stream = ttcInfos_[fontInfo.ttcIndex].stream;
366 if (stream == nullptr) {
367 return false;
368 }
369
370 FT_Error error = FT_Err_Ok;
371 if (FT_STREAM_SEEK(0)) {
372 return false;
373 }
374
375 // read ttc header
376 TtcHeader header = {};
377 static const FT_Frame_Field ttcHeaderFields[] = {
378 #undef FT_STRUCTURE
379 #define FT_STRUCTURE TtcHeader
380 FT_FRAME_START(12), // 12: see ttc header
381 FT_FRAME_ULONG(ttcTag), FT_FRAME_LONG(numFonts), FT_FRAME_END};
382 if (FT_STREAM_READ_FIELDS(ttcHeaderFields, &header)) {
383 return false;
384 }
385
386 // check if ttc file
387 if (header.ttcTag != TTAG_ttcf) { // 'ttcf' - TTC file
388 return false;
389 }
390
391 uint8_t ttfIndex = fontInfo.ttfIndex;
392 if (ttfIndex >= header.numFonts) {
393 // invalid index
394 return false;
395 }
396
397 // change position to the ttf offset
398 if (FT_STREAM_SKIP(4 * ttfIndex)) { // 4: table dictionary offset length
399 return false;
400 }
401
402 // get the ttf length
403 uint32_t ttfOffset;
404 if (FT_READ_ULONG(ttfOffset)) {
405 return false;
406 }
407 uint32_t ttfLength = 0;
408 FT_ULong ttcLength = stream->size;
409 if (ttcLength < ttfOffset) {
410 return false;
411 }
412 if (ttfIndex + 1 == header.numFonts) {
413 ttfLength = ttcLength - ttfOffset;
414 } else {
415 uint32_t nextTtfOffset;
416 if (FT_READ_ULONG(nextTtfOffset)) {
417 return false;
418 }
419 ttfLength = nextTtfOffset - ttfOffset;
420 }
421 if (ttfLength > ttfBufferSize) {
422 return false;
423 }
424 if (FT_STREAM_SEEK(ttfOffset) || FT_STREAM_READ(ttfBuffer, ttfLength)) {
425 return false;
426 }
427 ttfHeader.len = ttfLength;
428
429 // read number of tables
430 uint16_t numTables;
431 if (FT_STREAM_SEEK(ttfOffset + 4) || FT_READ_USHORT(numTables)) { // 4: sfntVersion length
432 return false;
433 }
434
435 // change the offset of the ttf tableRecord compare with ttfOffset from ttc header
436 uint32_t* p = reinterpret_cast<uint32_t*>(ttfBuffer + 20); // 20: 12(TableDirectory) + 8(tableTag and checksum)
437 for (uint16_t i = 0; i < numTables; i++) {
438 p[0] = FT_PEEK_ULONG(p) - ttfOffset;
439 p[0] = FT_PEEK_ULONG(p);
440 p += 4; // 4: Table Record size
441 }
442 return true;
443 }
IsVectorFont() const444 bool UIFontVector::IsVectorFont() const
445 {
446 return true;
447 }
448
GetFontWeight(uint16_t fontId)449 uint8_t UIFontVector::GetFontWeight(uint16_t fontId)
450 {
451 if (fontId >= FONT_ID_MAX) {
452 return BPP_BIT_8;
453 }
454
455 return fontInfo_[fontId].fontWeight;
456 }
457
SetFontPath(const char * path,FontType type)458 int8_t UIFontVector::SetFontPath(const char* path, FontType type)
459 {
460 if (path == nullptr) {
461 return INVALID_RET_VALUE;
462 }
463 ttfDir_ = path;
464 return RET_VALUE_OK;
465 }
466
GetFaceInfo(uint16_t fontId,uint8_t fontSize,FaceInfo & faceInfo)467 int8_t UIFontVector::GetFaceInfo(uint16_t fontId, uint8_t fontSize, FaceInfo& faceInfo)
468 {
469 if ((fontId >= FONT_ID_MAX) || (fontSize == 0)) {
470 return INVALID_RET_VALUE;
471 }
472
473 faceInfo.key = GetKey(fontId, fontSize);
474 faceInfo.face = ftFaces_[fontId];
475
476 if (fontSize_[fontId] == fontSize) {
477 return RET_VALUE_OK;
478 }
479 const UITextLanguageFontParam* fontInfo = GetFontInfo(fontId);
480 if ((fontInfo == nullptr) || (fontInfo->ttfName == nullptr)) {
481 return INVALID_RET_VALUE;
482 }
483
484 if (!freeTypeInited_) {
485 return INVALID_RET_VALUE;
486 }
487
488 // Set the size
489 int8_t ret;
490 if (IsEmojiFont(fontId)) {
491 ret = SetupColorFont(ftFaces_[fontId], fontSize);
492 } else {
493 ret = FT_Set_Char_Size(faceInfo.face, fontSize * FONT_PIXEL_IN_POINT, 0, 0, 0);
494 }
495
496 if (ret != 0) {
497 return INVALID_RET_VALUE;
498 }
499 fontSize_[fontId] = fontSize;
500 return RET_VALUE_OK;
501 }
502
GetHeight(uint16_t fontId,uint8_t fontSize)503 uint16_t UIFontVector::GetHeight(uint16_t fontId, uint8_t fontSize)
504 {
505 FaceInfo faceInfo;
506 int8_t ret = GetFaceInfo(fontId, fontSize, faceInfo);
507 if (ret != RET_VALUE_OK) {
508 return INVALID_RET_VALUE;
509 }
510 if (!freeTypeInited_ || (faceInfo.face == nullptr)) {
511 return 0;
512 }
513 return static_cast<uint16_t>(faceInfo.face->size->metrics.height / FONT_PIXEL_IN_POINT);
514 }
515
GetShapingFontId(char * text,uint8_t & ttfId,uint32_t & script,uint16_t fontId,uint8_t size) const516 uint16_t UIFontVector::GetShapingFontId(char* text, uint8_t& ttfId, uint32_t& script,
517 uint16_t fontId, uint8_t size) const
518 {
519 #if defined(ENABLE_MULTI_FONT) && ENABLE_MULTI_FONT
520 const UITextLanguageFontParam* fontParam1 = GetFontInfo(fontId);
521 if (fontParam1 == nullptr) {
522 return 0;
523 }
524 if (fontParam1->shaping == 0) {
525 if (!UIMultiFontManager::GetInstance()->IsNeedShaping(text, ttfId, script)) {
526 return 0; // 0 means no need to shape
527 }
528 uint16_t* searchLists = nullptr;
529 int8_t length = UIMultiFontManager::GetInstance()->GetSearchFontList(fontId, &searchLists);
530 const UITextLanguageFontParam* fontParam2 = nullptr;
531 for (uint8_t i = 0; i < length; i++) {
532 fontParam2 = GetFontInfo(searchLists[i]);
533 if (fontParam2 == nullptr) {
534 continue;
535 }
536 if (fontParam2->ttfId == ttfId) {
537 return fontParam2->shaping;
538 }
539 }
540 return 0;
541 }
542 ttfId = fontParam1->ttfId;
543
544 #if defined(ENABLE_SHAPING) && ENABLE_SHAPING
545 script = UIMultiFontManager::GetInstance()->GetScriptByTtfId(ttfId);
546 #endif
547 return fontParam1->shaping;
548 #else
549 const UITextLanguageFontParam* fontInfo = GetFontInfo(fontId);
550 if (fontInfo == nullptr) {
551 return 0;
552 }
553 ttfId = fontInfo->ttfId;
554 return fontInfo->shaping;
555 #endif
556 }
557
GetFontId(const char * ttfName,uint8_t fontSize) const558 uint16_t UIFontVector::GetFontId(const char* ttfName, uint8_t fontSize) const
559 {
560 if (ttfName != nullptr) {
561 int32_t i = 0;
562 while (i < FONT_ID_MAX) {
563 if ((fontInfo_[i].ttfName != nullptr) && (strstr(fontInfo_[i].ttfName, ttfName) != nullptr)) {
564 return static_cast<uint8_t>(i);
565 }
566 i++;
567 }
568 }
569
570 return FONT_ID_MAX;
571 }
572
GetFontId(uint32_t unicode) const573 uint16_t UIFontVector::GetFontId(uint32_t unicode) const
574 {
575 int32_t i = 0;
576 uint8_t ttfId = ((unicode >> 24) & 0x1F); // 24: Whether 25 ~29 bit storage is ttfId 0x1F:5bit
577 while (i < FONT_ID_MAX) {
578 if (fontInfo_[i].ttfName == nullptr) {
579 i++;
580 continue;
581 }
582 if (fontInfo_[i].ttfId == ttfId) {
583 return i;
584 }
585 i++;
586 }
587 return FONT_INVALID_TTF_ID;
588 }
589
GetWidth(uint32_t unicode,uint16_t fontId,uint8_t fontSize)590 int16_t UIFontVector::GetWidth(uint32_t unicode, uint16_t fontId, uint8_t fontSize)
591 {
592 if ((fontId >= FONT_ID_MAX) || (fontSize == 0)) {
593 return INVALID_RET_VALUE;
594 }
595
596 GlyphNode node;
597 int8_t ret = GetGlyphNode(unicode, node, fontId, fontSize);
598 if (ret != RET_VALUE_OK) {
599 return INVALID_RET_VALUE;
600 }
601 return node.advance;
602 }
603
GetFontHeader(FontHeader & fontHeader,uint16_t fontId,uint8_t fontSize)604 int8_t UIFontVector::GetFontHeader(FontHeader& fontHeader, uint16_t fontId, uint8_t fontSize)
605 {
606 FaceInfo faceInfo;
607 int8_t ret = GetFaceInfo(fontId, fontSize, faceInfo);
608 if (ret != RET_VALUE_OK) {
609 return INVALID_RET_VALUE;
610 }
611 if (!freeTypeInited_ || (faceInfo.face == nullptr)) {
612 return INVALID_RET_VALUE;
613 }
614
615 fontHeader.ascender = static_cast<int16_t>(faceInfo.face->size->metrics.ascender / FONT_PIXEL_IN_POINT);
616 fontHeader.descender = static_cast<int16_t>(faceInfo.face->size->metrics.descender / FONT_PIXEL_IN_POINT);
617 fontHeader.fontHeight = static_cast<uint16_t>(faceInfo.face->size->metrics.height / FONT_PIXEL_IN_POINT);
618 return RET_VALUE_OK;
619 }
620
SaveGlyphNode(uint32_t unicode,uint16_t fontKey,Metric * metric)621 void UIFontVector::SaveGlyphNode(uint32_t unicode, uint16_t fontKey, Metric *metric)
622 {
623 GlyphCacheNode* node = UIFontCacheManager::GetInstance()->GetNodeCacheSpace(unicode, fontKey);
624 if (node == nullptr) {
625 return;
626 }
627 node->node.left = metric->left;
628 node->node.top = metric->top;
629 node->node.cols = metric->cols;
630 node->node.rows = metric->rows;
631 node->node.advance = metric->advance;
632 node->node.unicode = unicode;
633 node->node.fontId = fontKey;
634 }
635
GetGlyphNode(uint32_t unicode,GlyphNode & glyphNode,uint16_t fontId,uint8_t fontSize)636 int8_t UIFontVector::GetGlyphNode(uint32_t unicode, GlyphNode& glyphNode, uint16_t fontId, uint8_t fontSize)
637 {
638 // get glyph from glyph cache
639 uint16_t fontKey = GetKey(fontId, fontSize);
640 GlyphCacheNode* cacheNode =
641 UIFontCacheManager::GetInstance()->GetNodeFromCache(unicode, fontKey, GlyphCacheType::CACHE_TYPE_NONE);
642 if (cacheNode != nullptr) {
643 glyphNode = cacheNode->node;
644 return RET_VALUE_OK;
645 }
646
647 #if defined(ENABLE_SPANNABLE_STRING) && ENABLE_SPANNABLE_STRING
648 uint8_t* bitmap = UIFontCacheManager::GetInstance()->GetBitmap(fontKey, unicode, glyphNode.textStyle);
649 #else
650 uint8_t* bitmap = UIFontCacheManager::GetInstance()->GetBitmap(fontKey, unicode);
651 #endif
652 if (bitmap != nullptr) {
653 Metric* f = reinterpret_cast<Metric*>(bitmap);
654 glyphNode.left = f->left;
655 glyphNode.top = f->top;
656 glyphNode.cols = f->cols;
657 glyphNode.rows = f->rows;
658 glyphNode.advance = f->advance;
659 glyphNode.fontId = fontId;
660
661 SaveGlyphNode(unicode, fontKey, f);
662 return RET_VALUE_OK;
663 }
664
665 FaceInfo faceInfo;
666 int8_t ret = GetFaceInfo(fontId, fontSize, faceInfo);
667 if (ret != RET_VALUE_OK) {
668 return INVALID_RET_VALUE;
669 }
670 if (faceInfo.face == nullptr) {
671 return INVALID_RET_VALUE;
672 }
673
674 int8_t error = LoadGlyphIntoFace(fontId, fontSize, unicode, glyphNode);
675 if (error != RET_VALUE_OK) {
676 return INVALID_RET_VALUE;
677 }
678
679 return RET_VALUE_OK;
680 }
681
GetBitmap(uint32_t unicode,GlyphNode & glyphNode,uint16_t fontId,uint8_t fontSize)682 uint8_t* UIFontVector::GetBitmap(uint32_t unicode, GlyphNode& glyphNode, uint16_t fontId, uint8_t fontSize)
683 {
684 uint16_t fontKey = GetKey(fontId, fontSize);
685 #if defined(ENABLE_SPANNABLE_STRING) && ENABLE_SPANNABLE_STRING
686 uint8_t* bitmap = UIFontCacheManager::GetInstance()->GetBitmap(fontKey, unicode, glyphNode.textStyle);
687 #else
688 uint8_t* bitmap = UIFontCacheManager::GetInstance()->GetBitmap(fontKey, unicode);
689 #endif
690 if (bitmap != nullptr) {
691 Metric* f = reinterpret_cast<Metric*>(bitmap);
692 glyphNode.left = f->left;
693 glyphNode.top = f->top;
694 glyphNode.cols = f->cols;
695 glyphNode.rows = f->rows;
696 glyphNode.advance = f->advance;
697 glyphNode.fontId = fontId;
698 SaveGlyphNode(unicode, fontKey, f);
699 return bitmap + sizeof(Metric);
700 }
701
702 FaceInfo faceInfo;
703 int8_t ret = GetFaceInfo(fontId, fontSize, faceInfo);
704 if (ret != RET_VALUE_OK) {
705 return nullptr;
706 }
707 if (faceInfo.face == nullptr) {
708 return nullptr;
709 }
710
711 int8_t error = LoadGlyphIntoFace(fontId, fontSize, unicode, glyphNode);
712 if (error != RET_VALUE_OK) {
713 return nullptr;
714 }
715
716 #if defined(ENABLE_SPANNABLE_STRING) && ENABLE_SPANNABLE_STRING
717 bitmap = UIFontCacheManager::GetInstance()->GetBitmap(fontKey, unicode, glyphNode.textStyle);
718 #else
719 bitmap = UIFontCacheManager::GetInstance()->GetBitmap(fontKey, unicode);
720 #endif
721 if (bitmap != nullptr) {
722 return bitmap + sizeof(Metric);
723 } else {
724 return nullptr;
725 }
726 }
727
IsEmojiFont(uint16_t fontId)728 bool UIFontVector::IsEmojiFont(uint16_t fontId)
729 {
730 if (fontId >= FONT_ID_MAX) {
731 return false;
732 }
733 return (fontInfo_[fontId].fontWeight >= 16); // 16: rgb color font
734 }
735
736 #if defined(ENABLE_SPANNABLE_STRING) && ENABLE_SPANNABLE_STRING
SetItaly(FT_GlyphSlot slot)737 void UIFontVector::SetItaly(FT_GlyphSlot slot)
738 {
739 if (slot->format != FT_GLYPH_FORMAT_OUTLINE) {
740 GRAPHIC_LOGE("SetItaly error");
741 return;
742 }
743 float lean = 0.2f; // Slope of word
744 FT_Matrix matrix;
745 matrix.xx = 0x10000L; // Staggered matrix along x-axis
746 matrix.xy = lean * 0x10000L;
747 matrix.yx = 0;
748 matrix.yy = 0x10000L; // Staggered matrix along y-axis
749 FT_Outline outline = slot->outline;
750 FT_Outline_Transform(&outline, &matrix);
751 }
752
SetBold(uint16_t fontId)753 void UIFontVector::SetBold(uint16_t fontId)
754 {
755 int32_t error;
756 FT_GlyphSlot slot = ftFaces_[fontId]->glyph;
757 // some reasonable strength, copied from freeType
758 FT_Pos xBold = FT_MulFix(ftFaces_[fontId]->units_per_EM, ftFaces_[fontId]->size->metrics.y_scale) / 24;
759 FT_Pos yBold = xBold;
760 if (ftFaces_[fontId]->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
761 FT_BBox oldBox;
762 FT_Outline_Get_CBox(&slot->outline, &oldBox);
763 error = FT_Outline_Embolden(&slot->outline, xBold);
764 if (error != 0) {
765 GRAPHIC_LOGE("SetBold error");
766 return;
767 }
768 } else if (ftFaces_[fontId]->glyph->format == FT_GLYPH_FORMAT_BITMAP) {
769 FT_Library ftLibrary = slot->library;
770 error = FT_Bitmap_Embolden(ftLibrary, &slot->bitmap, xBold, yBold);
771 if (error != 0) {
772 GRAPHIC_LOGE("SetBold error");
773 return;
774 }
775 }
776 }
777 #endif
778
LoadGlyphIntoFace(uint16_t & fontId,uint8_t fontSize,uint32_t unicode,GlyphNode & glyphNode)779 int8_t UIFontVector::LoadGlyphIntoFace(uint16_t& fontId, uint8_t fontSize, uint32_t unicode, GlyphNode& glyphNode)
780 {
781 int32_t error;
782 if (IsGlyphFont(unicode) != 0) {
783 if (fontId >= FONT_ID_MAX || fontId != GetFontId(unicode)) {
784 return INVALID_RET_VALUE;
785 }
786 error = FT_Load_Glyph(ftFaces_[fontId], unicode & (0xFFFFFF), FT_LOAD_RENDER);
787 } else {
788 if (IsEmojiFont(fontId)) {
789 error = FT_Load_Char(ftFaces_[fontId], unicode, FT_LOAD_COLOR);
790 } else {
791 error = FT_Load_Char(ftFaces_[fontId], unicode, FT_LOAD_RENDER);
792 }
793 }
794 if ((error != 0) || (ftFaces_[fontId]->glyph->glyph_index == 0)) {
795 return INVALID_RET_VALUE;
796 }
797
798 FaceInfo faceInfo;
799 faceInfo.key = GetKey(fontId, fontSize);
800 faceInfo.face = ftFaces_[fontId];
801
802 glyphNode.left = faceInfo.face->glyph->bitmap_left;
803 glyphNode.top = faceInfo.face->glyph->bitmap_top;
804 glyphNode.cols = faceInfo.face->glyph->bitmap.width;
805 glyphNode.rows = faceInfo.face->glyph->bitmap.rows;
806 glyphNode.advance = static_cast<uint16_t>(faceInfo.face->glyph->advance.x / FONT_PIXEL_IN_POINT);
807 glyphNode.fontId = fontId;
808
809 #if defined(ENABLE_SPANNABLE_STRING) && ENABLE_SPANNABLE_STRING
810 SetFace(faceInfo, unicode, glyphNode.textStyle);
811 #else
812 SetFace(faceInfo, unicode);
813 #endif
814 return RET_VALUE_OK;
815 }
816
817 #if defined(ENABLE_SPANNABLE_STRING) && ENABLE_SPANNABLE_STRING
LoadGlyphIntoFace(uint16_t & fontId,uint32_t unicode,FT_Face face,TextStyle textStyle)818 int8_t UIFontVector::LoadGlyphIntoFace(uint16_t& fontId, uint32_t unicode, FT_Face face, TextStyle textStyle)
819 {
820 int32_t error;
821 if (IsGlyphFont(unicode) != 0) {
822 if (fontId != GetFontId(unicode)) {
823 return INVALID_RET_VALUE;
824 }
825 unicode = unicode & (0xFFFFFF); // Whether 0 ~24 bit storage is unicode
826 error = FT_Load_Glyph(ftFaces_[fontId], unicode, FT_LOAD_RENDER);
827 } else {
828 if (IsEmojiFont(fontId)) {
829 error = FT_Load_Char(ftFaces_[fontId], unicode, FT_LOAD_COLOR);
830 } else {
831 error = FT_Load_Char(ftFaces_[fontId], unicode, FT_LOAD_RENDER);
832 }
833 }
834 if ((error != 0) || (ftFaces_[fontId]->glyph->glyph_index == 0)) {
835 return INVALID_RET_VALUE;
836 }
837 if (textStyle == TEXT_STYLE_ITALIC) {
838 SetItaly(ftFaces_[fontId]->glyph);
839 } else if (textStyle == TEXT_STYLE_BOLD) {
840 SetBold(fontId);
841 } else if (textStyle == TEXT_STYLE_BOLD_ITALIC) {
842 SetItaly(ftFaces_[fontId]->glyph);
843 SetBold(fontId);
844 }
845 if (ftFaces_[fontId]->glyph->format != FT_GLYPH_FORMAT_BITMAP) {
846 error = FT_Render_Glyph(ftFaces_[fontId]->glyph, FT_RENDER_MODE_NORMAL);
847 }
848 if ((error != 0) || (ftFaces_[fontId]->glyph->glyph_index == 0)) {
849 return INVALID_RET_VALUE;
850 }
851 return RET_VALUE_OK;
852 }
853 #endif
854
IsGlyphFont(uint32_t unicode)855 uint8_t UIFontVector::IsGlyphFont(uint32_t unicode)
856 {
857 uint16_t unicodeFontId = GetFontId(unicode);
858 if (unicodeFontId == FONT_INVALID_TTF_ID) {
859 return 0;
860 } else {
861 return fontInfo_[unicodeFontId].shaping;
862 }
863 }
864
SetFace(FaceInfo & faceInfo,uint32_t unicode)865 void UIFontVector::SetFace(FaceInfo& faceInfo, uint32_t unicode)
866 {
867 #if defined(ENABLE_SPANNABLE_STRING) && ENABLE_SPANNABLE_STRING
868 SetFace(faceInfo, unicode, TEXT_STYLE_NORMAL);
869 #else
870 Metric* f = reinterpret_cast<Metric*>(UIMalloc(sizeof(Metric)));
871 if (f == nullptr) {
872 return;
873 }
874 f->advance = static_cast<uint16_t>(faceInfo.face->glyph->advance.x / FONT_PIXEL_IN_POINT);
875 f->left = faceInfo.face->glyph->bitmap_left;
876 f->top = faceInfo.face->glyph->bitmap_top;
877 f->cols = faceInfo.face->glyph->bitmap.width;
878 f->rows = faceInfo.face->glyph->bitmap.rows;
879
880 // cache glyph
881 SaveGlyphNode(unicode, faceInfo.key, f);
882
883 int16_t pixSize;
884 ColorMode mode;
885 if (faceInfo.face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
886 pixSize = 0x04; // 4 Byte
887 mode = ARGB8888;
888 } else {
889 pixSize = 1;
890 mode = A8;
891 }
892
893 GlyphNode glyphNode;
894 glyphNode.left = f->left;
895 glyphNode.top = f->top;
896 glyphNode.cols = f->cols;
897 glyphNode.rows = f->rows;
898 glyphNode.advance = f->advance;
899 glyphNode.unicode = unicode;
900 glyphNode.fontId = faceInfo.key;
901 BufferInfo bufInfo = UIFontAllocator::GetCacheBuffer(faceInfo.key, unicode, mode, glyphNode, true);
902 uint32_t bitmapSize = bufInfo.stride * bufInfo.height;
903 uint32_t rawSize = glyphNode.cols * glyphNode.rows * pixSize;
904
905 if (bufInfo.virAddr != nullptr) {
906 if (memcpy_s(bufInfo.virAddr, sizeof(Metric), f, sizeof(Metric)) != EOK) {
907 UIFontCacheManager::GetInstance()->PutSpace(reinterpret_cast<uint8_t*>(bufInfo.virAddr));
908 UIFree(f);
909 return;
910 }
911 if ((faceInfo.face->glyph->bitmap.buffer != nullptr) &&
912 (memcpy_s(reinterpret_cast<uint8_t*>(bufInfo.virAddr) + sizeof(Metric), bitmapSize,
913 faceInfo.face->glyph->bitmap.buffer, rawSize) != EOK)) {
914 UIFontCacheManager::GetInstance()->PutSpace(reinterpret_cast<uint8_t*>(bufInfo.virAddr));
915 UIFree(f);
916 return;
917 }
918 UIFontAllocator::RearrangeBitmap(bufInfo, rawSize, true);
919 ClearFontGlyph(faceInfo.face);
920 }
921 UIFree(f);
922 #endif
923 }
924
925 #if defined(ENABLE_SPANNABLE_STRING) && ENABLE_SPANNABLE_STRING
SetFace(FaceInfo & faceInfo,uint32_t unicode,TextStyle textStyle)926 void UIFontVector::SetFace(FaceInfo& faceInfo, uint32_t unicode, TextStyle textStyle)
927 {
928 Metric f;
929 f.advance = static_cast<uint16_t>(faceInfo.face->glyph->advance.x / FONT_PIXEL_IN_POINT);
930 f.left = faceInfo.face->glyph->bitmap_left;
931 f.top = faceInfo.face->glyph->bitmap_top;
932 f.cols = faceInfo.face->glyph->bitmap.width;
933 f.rows = faceInfo.face->glyph->bitmap.rows;
934
935 // cache glyph
936 SaveGlyphNode(unicode, faceInfo.key, &f);
937
938 int16_t pixSize = 1;
939 if (faceInfo.face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
940 pixSize = 0x04; // 4 Byte
941 }
942 uint32_t bitmapSize = faceInfo.face->glyph->bitmap.width * faceInfo.face->glyph->bitmap.rows * pixSize;
943 // cache bitmap
944 uint8_t* bitmap =
945 UIFontCacheManager::GetInstance()->GetSpace(faceInfo.key, unicode, bitmapSize + sizeof(Metric), textStyle);
946 if (bitmap != nullptr) {
947 if (memcpy_s(bitmap, sizeof(Metric), &f, sizeof(Metric)) != EOK) {
948 UIFontCacheManager::GetInstance()->PutSpace(bitmap);
949 return;
950 }
951 if (memcpy_s(bitmap + sizeof(Metric), bitmapSize, faceInfo.face->glyph->bitmap.buffer, bitmapSize) != EOK) {
952 UIFontCacheManager::GetInstance()->PutSpace(bitmap);
953 return;
954 }
955 ClearFontGlyph(faceInfo.face);
956 }
957 }
958 #endif
959
ClearFontGlyph(FT_Face face)960 void UIFontVector::ClearFontGlyph(FT_Face face)
961 {
962 if ((face != nullptr) && (face->glyph != nullptr)) {
963 // free unicode buffer immediately to save memory in multi font file load
964 // if not, it will be freed in next glyph load
965 ft_glyphslot_free_bitmap(face->glyph);
966 FT_Outline_Done(face->glyph->library, &face->glyph->outline);
967 if (face->glyph->internal != nullptr) {
968 FT_GlyphLoader_Reset(face->glyph->internal->loader);
969 }
970 }
971 }
972
GetKey(uint16_t fontId,uint8_t size)973 inline uint16_t UIFontVector::GetKey(uint16_t fontId, uint8_t size)
974 {
975 return ((static_cast<uint16_t>(fontId)) << 8) + size; // fontId store at the (8+1)th bit
976 }
977
GetOffsetPosY(const char * text,uint16_t lineLength,bool & isEmojiLarge,uint16_t fontId,uint8_t fontSize)978 uint16_t UIFontVector::GetOffsetPosY(const char* text,
979 uint16_t lineLength,
980 bool& isEmojiLarge,
981 uint16_t fontId,
982 uint8_t fontSize)
983 {
984 if (!freeTypeInited_) {
985 return INVALID_RET_VALUE;
986 }
987 uint32_t i = 0;
988 uint16_t textNum = 0;
989 uint16_t emojiNum = 0;
990 uint16_t loopNum = 0;
991 GlyphNode glyphNode;
992 GlyphNode emojiMaxNode = {};
993 uint8_t maxFontSize = fontSize;
994 while (i < lineLength) {
995 uint32_t unicode = TypedText::GetUTF8Next(text, i, i);
996 uint8_t ret = GetGlyphNode(unicode, glyphNode, fontId, fontSize);
997 if (ret == RET_VALUE_OK) {
998 uint8_t weight = GetFontWeight(glyphNode.fontId);
999 // 16: bit rgb565 rgba8888
1000 if (weight >= 16) {
1001 emojiMaxNode = glyphNode.rows > emojiMaxNode.rows ? glyphNode : emojiMaxNode;
1002 emojiNum++;
1003 } else {
1004 textNum++;
1005 }
1006 loopNum++;
1007 }
1008 }
1009 // The number of emoji is the same as the number of cycles, indicating that this line is all emoji
1010 // The number of words is the same as the number of cycles, which means that this line is all words
1011 if ((emojiNum == loopNum) || (textNum == loopNum)) {
1012 isEmojiLarge = true;
1013 return 0;
1014 }
1015 isEmojiLarge = emojiMaxNode.rows > maxFontSize;
1016 uint16_t offset = 0;
1017 if (isEmojiLarge) {
1018 // If the emoji is higher than the text
1019 if (emojiMaxNode.top >= maxFontSize) {
1020 offset = emojiMaxNode.top - maxFontSize;
1021 }
1022 } else {
1023 // If text are higher than emoji
1024 if (maxFontSize >= emojiMaxNode.rows) {
1025 offset = maxFontSize - emojiMaxNode.rows;
1026 }
1027 }
1028 return offset;
1029 }
1030
GetLineMaxHeight(const char * text,uint16_t lineLength,uint16_t fontId,uint8_t fontSize,uint16_t & letterIndex,SizeSpan * sizeSpans)1031 uint16_t UIFontVector::GetLineMaxHeight(const char* text,
1032 uint16_t lineLength,
1033 uint16_t fontId,
1034 uint8_t fontSize,
1035 uint16_t& letterIndex,
1036 SizeSpan* sizeSpans)
1037 {
1038 if (!freeTypeInited_) {
1039 return INVALID_RET_VALUE;
1040 }
1041 uint32_t i = 0;
1042 uint16_t textNum = 0;
1043 uint16_t emojiNum = 0;
1044 uint16_t loopNum = 0;
1045 uint16_t maxHeight = GetHeight(fontId, fontSize);
1046 while (i < lineLength) {
1047 uint32_t unicode = TypedText::GetUTF8Next(text, i, i);
1048 TypedText::IsColourWord(unicode, fontId, fontSize) ? emojiNum++ : textNum++;
1049 loopNum++;
1050 if (sizeSpans != nullptr && sizeSpans[letterIndex].isSizeSpan) {
1051 uint16_t spannableHeight = 0;
1052 if (sizeSpans[letterIndex].height == 0) {
1053 spannableHeight = GetHeight(sizeSpans[letterIndex].fontId, sizeSpans[letterIndex].size);
1054 sizeSpans[letterIndex].height = spannableHeight;
1055 } else {
1056 spannableHeight = sizeSpans[letterIndex].height;
1057 }
1058 maxHeight = spannableHeight > maxHeight ? spannableHeight : maxHeight;
1059 }
1060 letterIndex++;
1061 if (i > 0 && ((text[i - 1] == '\r') || (text[i - 1] == '\n'))) {
1062 break;
1063 }
1064 }
1065 return GetMaxSubLineHeight(textNum, loopNum, maxHeight, emojiNum);
1066 }
1067
GetMaxSubLineHeight(uint16_t textNum,uint16_t loopNum,uint16_t maxHeight,uint16_t emojiNum)1068 uint16_t UIFontVector::GetMaxSubLineHeight(uint16_t textNum, uint16_t loopNum, uint16_t maxHeight, uint16_t emojiNum)
1069 {
1070 // The number of words is the same as the number of cycles, which means that this line is all words
1071 if (textNum == loopNum) {
1072 for (uint8_t i = 0; i < currentFontInfoNum_; i++) {
1073 if (!IsEmojiFont(i)) {
1074 uint16_t height = static_cast<uint16_t>(ftFaces_[i]->size->metrics.height / FONT_PIXEL_IN_POINT);
1075 if (height > maxHeight) {
1076 maxHeight = height;
1077 }
1078 return maxHeight;
1079 }
1080 }
1081 }
1082 // The number of emoji is the same as the number of cycles, indicating that this line is all emoji
1083 if (emojiNum == loopNum) {
1084 for (uint8_t i = 0; i < currentFontInfoNum_; i++) {
1085 if (IsEmojiFont(i)) {
1086 return static_cast<uint16_t>(ftFaces_[i]->size->metrics.height / FONT_PIXEL_IN_POINT);
1087 }
1088 }
1089 }
1090 // A line has both emoji and words
1091 if ((textNum > 0) && (emojiNum > 0)) {
1092 for (uint8_t i = 0; i < currentFontInfoNum_; i++) {
1093 uint16_t tmpHeight = static_cast<uint16_t>(ftFaces_[i]->size->metrics.height / FONT_PIXEL_IN_POINT);
1094 maxHeight = tmpHeight > maxHeight ? tmpHeight : maxHeight;
1095 }
1096 }
1097 return maxHeight;
1098 }
1099
SetPsramMemory(uintptr_t psramAddr,uint32_t psramLen)1100 void UIFontVector::SetPsramMemory(uintptr_t psramAddr, uint32_t psramLen)
1101 {
1102 BaseFont::SetPsramMemory(psramAddr, psramLen);
1103 FontRamAllocator::GetInstance().SetRamAddr(psramAddr, psramLen);
1104 }
1105
SetCurrentLangId(uint8_t langId)1106 int8_t UIFontVector::SetCurrentLangId(uint8_t langId)
1107 {
1108 FontRamAllocator::GetInstance().ClearRam();
1109 #if defined(ENABLE_SHAPING) && ENABLE_SHAPING
1110 UITextShaping::GetInstance()->ClearTtfHeader();
1111 #endif
1112 UIFontCacheManager::GetInstance()->ClearCacheFlag();
1113 UIFontCacheManager::GetInstance()->BitmapCacheClear();
1114
1115 if (UIFontCacheManager::GetInstance()->GlyphsCacheInit() != RET_VALUE_OK) {
1116 GRAPHIC_LOGE("UIFontCacheManager::GlyphsCacheInit init failed");
1117 return INVALID_RET_VALUE;
1118 }
1119
1120 UIFontCacheManager::GetInstance()->BitmapCacheInit();
1121 return RET_VALUE_OK;
1122 }
1123 } // namespace OHOS
1124