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 #include <freetype/ftbitmap.h>
18 #include <freetype/ftoutln.h>
19 #include <freetype/internal/ftobjs.h>
20 #include <freetype/internal/ftstream.h>
21 #include <freetype/tttags.h>
22 
23 #include "common/typed_text.h"
24 #include "draw/draw_utils.h"
25 #include "font/font_ram_allocator.h"
26 #include "font/ui_font_cache_manager.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 
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 
516 uint16_t
GetShapingFontId(char * text,uint8_t & ttfId,uint32_t & script,uint16_t fontId,uint8_t size) const517     UIFontVector::GetShapingFontId(char* text, uint8_t& ttfId, uint32_t& script, 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         UIMultiFontManager* multiFontManager = UIMultiFontManager::GetInstance();
526         if (!multiFontManager->IsNeedShaping(text, ttfId, script)) {
527             return 0; // 0 means  no need to shape
528         }
529         uint16_t* searchLists = nullptr;
530         int8_t length = multiFontManager->GetSearchFontList(fontId, &searchLists);
531         const UITextLanguageFontParam* fontParam2 = nullptr;
532         for (uint8_t i = 0; i < length; i++) {
533             fontParam2 = GetFontInfo(searchLists[i]);
534             if (fontParam2 == nullptr) {
535                 continue;
536             }
537             if (fontParam2->ttfId == ttfId) {
538                 return fontParam2->shaping;
539             }
540         }
541         return 0;
542     }
543     ttfId = fontParam1->ttfId;
544 
545 #if defined(ENABLE_SHAPING) && ENABLE_SHAPING
546     script = UIMultiFontManager::GetInstance()->GetScriptByTtfId(ttfId);
547 #endif
548     return fontParam1->shaping;
549 #else
550     const UITextLanguageFontParam* fontInfo = GetFontInfo(fontId);
551     if (fontInfo == nullptr) {
552         return 0;
553     }
554     ttfId = fontInfo->ttfId;
555     return fontInfo->shaping;
556 #endif
557 }
558 
GetFontId(const char * ttfName,uint8_t fontSize) const559 uint16_t UIFontVector::GetFontId(const char* ttfName, uint8_t fontSize) const
560 {
561     if (ttfName != nullptr) {
562         int32_t i = 0;
563         while (i < FONT_ID_MAX) {
564             if ((fontInfo_[i].ttfName != nullptr) && (strstr(fontInfo_[i].ttfName, ttfName) != nullptr)) {
565                 return static_cast<uint16_t>(i);
566             }
567             i++;
568         }
569     }
570 
571     return static_cast<uint16_t>(FONT_ID_MAX);
572 }
573 
GetFontId(uint32_t unicode) const574 uint16_t UIFontVector::GetFontId(uint32_t unicode) const
575 {
576     int32_t i = 0;
577     uint8_t ttfId = ((unicode >> 24) & 0x1F); // 24: Whether 25 ~29 bit storage is ttfId 0x1F:5bit
578     while (i < FONT_ID_MAX) {
579         if (fontInfo_[i].ttfName == nullptr) {
580             i++;
581             continue;
582         }
583         if (fontInfo_[i].ttfId == ttfId) {
584             return i;
585         }
586         i++;
587     }
588     return FONT_INVALID_TTF_ID;
589 }
590 
GetWidth(uint32_t unicode,uint16_t fontId,uint8_t fontSize)591 int16_t UIFontVector::GetWidth(uint32_t unicode, uint16_t fontId, uint8_t fontSize)
592 {
593     if ((fontId >= FONT_ID_MAX) || (fontSize == 0)) {
594         return INVALID_RET_VALUE;
595     }
596 
597     GlyphNode node;
598     int8_t ret = GetGlyphNode(unicode, node, fontId, fontSize);
599     if (ret != RET_VALUE_OK) {
600         return INVALID_RET_VALUE;
601     }
602     return node.advance;
603 }
604 
GetFontHeader(FontHeader & fontHeader,uint16_t fontId,uint8_t fontSize)605 int8_t UIFontVector::GetFontHeader(FontHeader& fontHeader, uint16_t fontId, uint8_t fontSize)
606 {
607     FaceInfo faceInfo;
608     int8_t ret = GetFaceInfo(fontId, fontSize, faceInfo);
609     if (ret != RET_VALUE_OK) {
610         return INVALID_RET_VALUE;
611     }
612     if (!freeTypeInited_ || (faceInfo.face == nullptr)) {
613         return INVALID_RET_VALUE;
614     }
615 
616     fontHeader.ascender = static_cast<int16_t>(faceInfo.face->size->metrics.ascender / FONT_PIXEL_IN_POINT);
617     fontHeader.descender = static_cast<int16_t>(faceInfo.face->size->metrics.descender / FONT_PIXEL_IN_POINT);
618     fontHeader.fontHeight = static_cast<uint16_t>(faceInfo.face->size->metrics.height / FONT_PIXEL_IN_POINT);
619     return RET_VALUE_OK;
620 }
621 
SaveGlyphNode(uint32_t unicode,uint16_t fontKey,Metric * metric)622 void UIFontVector::SaveGlyphNode(uint32_t unicode, uint16_t fontKey, Metric *metric)
623 {
624     GlyphCacheNode* node = UIFontCacheManager::GetInstance()->GetNodeCacheSpace(unicode, fontKey);
625     if (node == nullptr) {
626         return;
627     }
628     node->node.left = metric->left;
629     node->node.top = metric->top;
630     node->node.cols = metric->cols;
631     node->node.rows = metric->rows;
632     node->node.advance = metric->advance;
633     node->node.unicode = unicode;
634     node->node.fontId = fontKey;
635 }
636 
GetGlyphNode(uint32_t unicode,GlyphNode & glyphNode,uint16_t fontId,uint8_t fontSize)637 int8_t UIFontVector::GetGlyphNode(uint32_t unicode, GlyphNode& glyphNode, uint16_t fontId, uint8_t fontSize)
638 {
639     // get glyph from glyph cache
640     uint16_t fontKey = GetKey(fontId, fontSize);
641     UIFontCacheManager* fontCacheManager = UIFontCacheManager::GetInstance();
642     GlyphCacheNode* cacheNode = fontCacheManager->GetNodeFromCache(unicode, fontKey, GlyphCacheType::CACHE_TYPE_NONE);
643     if (cacheNode != nullptr) {
644         glyphNode = cacheNode->node;
645         return RET_VALUE_OK;
646     }
647 
648 #if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
649     uint8_t* bitmap = fontCacheManager->GetBitmap(fontKey, unicode, glyphNode.textStyle);
650 #else
651     uint8_t* bitmap = fontCacheManager->GetBitmap(fontKey, unicode, TEXT_STYLE_NORMAL);
652 #endif
653     if (bitmap != nullptr) {
654         Metric* f = reinterpret_cast<Metric*>(bitmap);
655         glyphNode.left = f->left;
656         glyphNode.top = f->top;
657         glyphNode.cols = f->cols;
658         glyphNode.rows = f->rows;
659         glyphNode.advance = f->advance;
660         glyphNode.fontId = fontId;
661 
662         SaveGlyphNode(unicode, fontKey, f);
663         return RET_VALUE_OK;
664     }
665 
666     FaceInfo faceInfo;
667     int8_t ret = GetFaceInfo(fontId, fontSize, faceInfo);
668     if (ret != RET_VALUE_OK) {
669         return INVALID_RET_VALUE;
670     }
671     if (faceInfo.face == nullptr) {
672         return INVALID_RET_VALUE;
673     }
674 
675     int8_t error = LoadGlyphIntoFace(fontId, fontSize, unicode, glyphNode);
676     if (error != RET_VALUE_OK) {
677         return INVALID_RET_VALUE;
678     }
679 
680     return RET_VALUE_OK;
681 }
682 
GetBitmap(uint32_t unicode,GlyphNode & glyphNode,uint16_t fontId,uint8_t fontSize)683 uint8_t* UIFontVector::GetBitmap(uint32_t unicode, GlyphNode& glyphNode, uint16_t fontId, uint8_t fontSize)
684 {
685     uint16_t fontKey = GetKey(fontId, fontSize);
686     UIFontCacheManager* fontCacheManager = UIFontCacheManager::GetInstance();
687 #if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
688     uint8_t* bitmap = fontCacheManager->GetBitmap(fontKey, unicode, glyphNode.textStyle);
689 #else
690     uint8_t* bitmap = fontCacheManager->GetBitmap(fontKey, unicode, TEXT_STYLE_NORMAL);
691 #endif
692     if (bitmap != nullptr) {
693         Metric* f = reinterpret_cast<Metric*>(bitmap);
694         glyphNode.left = f->left;
695         glyphNode.top = f->top;
696         glyphNode.cols = f->cols;
697         glyphNode.rows = f->rows;
698         glyphNode.advance = f->advance;
699         glyphNode.fontId = fontId;
700         SaveGlyphNode(unicode, fontKey, f);
701         return bitmap + sizeof(Metric);
702     }
703     FaceInfo faceInfo;
704     int8_t ret = GetFaceInfo(fontId, fontSize, faceInfo);
705     if (ret != RET_VALUE_OK) {
706         return nullptr;
707     }
708     if (faceInfo.face == nullptr) {
709         return nullptr;
710     }
711 
712     int8_t error = LoadGlyphIntoFace(fontId, fontSize, unicode, glyphNode);
713     if (error != RET_VALUE_OK) {
714         return nullptr;
715     }
716 
717 #if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
718     bitmap = fontCacheManager->GetBitmap(fontKey, unicode, glyphNode.textStyle);
719 #else
720     bitmap = fontCacheManager->GetBitmap(fontKey, unicode, TEXT_STYLE_NORMAL);
721 #endif
722     if (bitmap != nullptr) {
723         return bitmap + sizeof(Metric);
724     } else {
725         return nullptr;
726     }
727 }
728 
IsEmojiFont(uint16_t fontId)729 bool UIFontVector::IsEmojiFont(uint16_t fontId)
730 {
731     if (fontId >= FONT_ID_MAX) {
732         return false;
733     }
734     return (fontInfo_[fontId].fontWeight >= 16); // 16: rgb color font
735 }
736 
737 #if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
SetItaly(FT_GlyphSlot slot)738 void UIFontVector::SetItaly(FT_GlyphSlot slot)
739 {
740     if (slot->format != FT_GLYPH_FORMAT_OUTLINE) {
741         GRAPHIC_LOGE("SetItaly error");
742         return;
743     }
744     float lean = 0.2f; // Slope of word
745     FT_Matrix matrix;
746     matrix.xx = 0x10000L; // Staggered matrix along x-axis
747     matrix.xy = lean * 0x10000L;
748     matrix.yx = 0;
749     matrix.yy = 0x10000L; // Staggered matrix along y-axis
750     FT_Outline outline = slot->outline;
751     FT_Outline_Transform(&outline, &matrix);
752 }
753 #endif
754 
755 #if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
SetBold(uint16_t fontId)756 void UIFontVector::SetBold(uint16_t fontId)
757 {
758     int32_t error;
759     FT_GlyphSlot slot = ftFaces_[fontId]->glyph;
760     // some reasonable strength, copied from freeType
761     FT_Pos xBold = FT_MulFix(ftFaces_[fontId]->units_per_EM, ftFaces_[fontId]->size->metrics.y_scale) / 24;
762     FT_Pos yBold = xBold;
763     if (ftFaces_[fontId]->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
764         FT_BBox oldBox;
765         FT_Outline_Get_CBox(&slot->outline, &oldBox);
766         error = FT_Outline_Embolden(&slot->outline, xBold);
767         if (error != 0) {
768             GRAPHIC_LOGE("SetBold error");
769             return;
770         }
771     } else if (ftFaces_[fontId]->glyph->format == FT_GLYPH_FORMAT_BITMAP) {
772         FT_Library ftLibrary = slot->library;
773         error = FT_Bitmap_Embolden(ftLibrary, &slot->bitmap, xBold, yBold);
774         if (error != 0) {
775             GRAPHIC_LOGE("SetBold error");
776             return;
777         }
778     }
779 }
780 #endif
781 
LoadGlyphIntoFace(uint16_t & fontId,uint8_t fontSize,uint32_t unicode,GlyphNode & glyphNode)782 int8_t UIFontVector::LoadGlyphIntoFace(uint16_t& fontId, uint8_t fontSize, uint32_t unicode, GlyphNode& glyphNode)
783 {
784     int32_t error;
785     if (IsGlyphFont(unicode) != 0) {
786         if (fontId >= FONT_ID_MAX || fontId != GetFontId(unicode)) {
787             return INVALID_RET_VALUE;
788         }
789         error = FT_Load_Glyph(ftFaces_[fontId], unicode & (0xFFFFFF), FT_LOAD_RENDER);
790     } else {
791         if (IsEmojiFont(fontId)) {
792             error = FT_Load_Char(ftFaces_[fontId], unicode, FT_LOAD_COLOR);
793         } else {
794             error = FT_Load_Char(ftFaces_[fontId], unicode, FT_LOAD_RENDER);
795         }
796     }
797     if ((error != 0) || (ftFaces_[fontId]->glyph->glyph_index == 0)) {
798         return INVALID_RET_VALUE;
799     }
800 
801     FaceInfo faceInfo;
802     faceInfo.key = GetKey(fontId, fontSize);
803     faceInfo.face = ftFaces_[fontId];
804 
805     glyphNode.left = faceInfo.face->glyph->bitmap_left;
806     glyphNode.top = faceInfo.face->glyph->bitmap_top;
807     glyphNode.cols = faceInfo.face->glyph->bitmap.width;
808     glyphNode.rows = faceInfo.face->glyph->bitmap.rows;
809     glyphNode.advance = static_cast<uint16_t>(faceInfo.face->glyph->advance.x / FONT_PIXEL_IN_POINT);
810     glyphNode.fontId = fontId;
811 
812 #if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
813     SetFace(faceInfo, unicode, glyphNode.textStyle);
814 #else
815     SetFace(faceInfo, unicode);
816 #endif
817     return RET_VALUE_OK;
818 }
819 
820 #if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
LoadGlyphIntoFace(uint16_t & fontId,uint32_t unicode,FT_Face face,TextStyle textStyle)821 int8_t UIFontVector::LoadGlyphIntoFace(uint16_t& fontId, uint32_t unicode, FT_Face face, TextStyle textStyle)
822 {
823     int32_t error;
824     if (IsGlyphFont(unicode) != 0) {
825         if (fontId != GetFontId(unicode)) {
826             return INVALID_RET_VALUE;
827         }
828         unicode = unicode & (0xFFFFFF); // Whether 0 ~24 bit storage is unicode
829         error = FT_Load_Glyph(ftFaces_[fontId], unicode, FT_LOAD_RENDER);
830     } else {
831         if (IsEmojiFont(fontId)) {
832             error = FT_Load_Char(ftFaces_[fontId], unicode, FT_LOAD_COLOR);
833         } else {
834             error = FT_Load_Char(ftFaces_[fontId], unicode, FT_LOAD_RENDER);
835         }
836     }
837     if ((error != 0) || (ftFaces_[fontId]->glyph->glyph_index == 0)) {
838         return INVALID_RET_VALUE;
839     }
840     if (textStyle == TEXT_STYLE_ITALIC) {
841         SetItaly(ftFaces_[fontId]->glyph);
842     } else if (textStyle == TEXT_STYLE_BOLD) {
843         SetBold(fontId);
844     } else if (textStyle == TEXT_STYLE_BOLD_ITALIC) {
845         SetItaly(ftFaces_[fontId]->glyph);
846         SetBold(fontId);
847     }
848     if (ftFaces_[fontId]->glyph->format != FT_GLYPH_FORMAT_BITMAP) {
849         error = FT_Render_Glyph(ftFaces_[fontId]->glyph, FT_RENDER_MODE_NORMAL);
850     }
851     if ((error != 0) || (ftFaces_[fontId]->glyph->glyph_index == 0)) {
852         return INVALID_RET_VALUE;
853     }
854     return RET_VALUE_OK;
855 }
856 #endif
857 
IsGlyphFont(uint32_t unicode)858 uint8_t UIFontVector::IsGlyphFont(uint32_t unicode)
859 {
860     uint16_t unicodeFontId = GetFontId(unicode);
861     if (unicodeFontId == FONT_INVALID_TTF_ID) {
862         return 0;
863     } else {
864         return fontInfo_[unicodeFontId].shaping;
865     }
866 }
867 
SetFace(FaceInfo & faceInfo,uint32_t unicode)868 void UIFontVector::SetFace(FaceInfo& faceInfo, uint32_t unicode)
869 {
870     SetFace(faceInfo, unicode, TEXT_STYLE_NORMAL);
871 }
872 
SetFace(FaceInfo & faceInfo,uint32_t unicode,TextStyle textStyle)873 void UIFontVector::SetFace(FaceInfo& faceInfo, uint32_t unicode, TextStyle textStyle)
874 {
875     Metric* f = reinterpret_cast<Metric*>(UIMalloc(sizeof(Metric)));
876     if (f == nullptr) {
877         return;
878     }
879     f->advance = static_cast<uint16_t>(faceInfo.face->glyph->advance.x / FONT_PIXEL_IN_POINT);
880     f->left = faceInfo.face->glyph->bitmap_left;
881     f->top = faceInfo.face->glyph->bitmap_top;
882     f->cols = faceInfo.face->glyph->bitmap.width;
883     f->rows = faceInfo.face->glyph->bitmap.rows;
884 
885     // cache glyph
886     SaveGlyphNode(unicode, faceInfo.key, f);
887 
888     int16_t pixSize;
889     ColorMode mode;
890     if (faceInfo.face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
891         pixSize = 0x04; // 4 Byte
892         mode = ARGB8888;
893     } else {
894         pixSize = 1;
895         mode = A8;
896     }
897 
898     GlyphNode glyphNode;
899     glyphNode.left = f->left;
900     glyphNode.top = f->top;
901     glyphNode.cols = f->cols;
902     glyphNode.rows = f->rows;
903     glyphNode.advance = f->advance;
904     glyphNode.unicode = unicode;
905     glyphNode.fontId = faceInfo.key;
906     BufferInfo bufInfo = UIFontAllocator::GetCacheBuffer(faceInfo.key, unicode, mode, glyphNode, true, textStyle);
907     uint32_t bitmapSize = bufInfo.stride * bufInfo.height;
908     uint32_t rawSize = glyphNode.cols * glyphNode.rows * pixSize;
909 
910     if (bufInfo.virAddr != nullptr) {
911         if (memcpy_s(bufInfo.virAddr, sizeof(Metric), f, sizeof(Metric)) != EOK) {
912             UIFontCacheManager::GetInstance()->PutSpace(reinterpret_cast<uint8_t*>(bufInfo.virAddr));
913             UIFree(f);
914             return;
915         }
916         if ((faceInfo.face->glyph->bitmap.buffer != nullptr) &&
917             (memcpy_s(reinterpret_cast<uint8_t*>(bufInfo.virAddr) + sizeof(Metric), bitmapSize,
918                       faceInfo.face->glyph->bitmap.buffer, rawSize) != EOK)) {
919             UIFontCacheManager::GetInstance()->PutSpace(reinterpret_cast<uint8_t*>(bufInfo.virAddr));
920             UIFree(f);
921             return;
922         }
923         UIFontAllocator::RearrangeBitmap(bufInfo, rawSize, true);
924         ClearFontGlyph(faceInfo.face);
925     }
926     UIFree(f);
927 }
928 
ClearFontGlyph(FT_Face face)929 void UIFontVector::ClearFontGlyph(FT_Face face)
930 {
931     if ((face != nullptr) && (face->glyph != nullptr)) {
932         // free unicode buffer immediately to save memory in multi font file load
933         // if not, it will be freed in next glyph load
934         ft_glyphslot_free_bitmap(face->glyph);
935         FT_Outline_Done(face->glyph->library, &face->glyph->outline);
936         if (face->glyph->internal != nullptr) {
937             FT_GlyphLoader_Reset(face->glyph->internal->loader);
938         }
939     }
940 }
941 
GetKey(uint16_t fontId,uint8_t size)942 inline uint16_t UIFontVector::GetKey(uint16_t fontId, uint8_t size)
943 {
944     return ((static_cast<uint16_t>(fontId)) << 8) + size; // fontId store at the (8+1)th bit
945 }
946 
GetOffsetPosY(const char * text,uint16_t lineLength,bool & isEmojiLarge,uint16_t fontId,uint8_t fontSize)947 uint16_t UIFontVector::GetOffsetPosY(const char* text,
948                                      uint16_t lineLength,
949                                      bool& isEmojiLarge,
950                                      uint16_t fontId,
951                                      uint8_t fontSize)
952 {
953     if (!freeTypeInited_) {
954         return INVALID_RET_VALUE;
955     }
956     uint32_t i = 0;
957     uint16_t textNum = 0;
958     uint16_t emojiNum = 0;
959     uint16_t loopNum = 0;
960     GlyphNode glyphNode;
961     GlyphNode emojiMaxNode = {};
962     uint8_t maxFontSize = fontSize;
963     while (i < lineLength) {
964         uint32_t unicode = TypedText::GetUTF8Next(text, i, i);
965         uint8_t ret = GetGlyphNode(unicode, glyphNode, fontId, fontSize);
966         if (ret == RET_VALUE_OK) {
967             uint8_t weight = GetFontWeight(glyphNode.fontId);
968             // 16: bit rgb565 rgba8888
969             if (weight >= 16) {
970                 emojiMaxNode = glyphNode.rows > emojiMaxNode.rows ? glyphNode : emojiMaxNode;
971                 emojiNum++;
972             } else {
973                 textNum++;
974             }
975             loopNum++;
976         }
977     }
978     // The number of emoji is the same as the number of cycles, indicating that this line is all emoji
979     // The number of words is the same as the number of cycles, which means that this line is all words
980     if ((emojiNum == loopNum) || (textNum == loopNum)) {
981         isEmojiLarge = true;
982         return 0;
983     }
984     isEmojiLarge = emojiMaxNode.rows > maxFontSize;
985     uint16_t offset = 0;
986     if (isEmojiLarge) {
987         // If the emoji is higher than the text
988         if (emojiMaxNode.top >= maxFontSize) {
989             offset = emojiMaxNode.top - maxFontSize;
990         }
991     } else {
992         // If text are higher than emoji
993         if (maxFontSize >= emojiMaxNode.rows) {
994             offset = maxFontSize - emojiMaxNode.rows;
995         }
996     }
997     return offset;
998 }
999 
GetLineMaxHeight(const char * text,uint16_t lineLength,uint16_t fontId,uint8_t fontSize,uint16_t & letterIndex,SpannableString * spannableString)1000 uint16_t UIFontVector::GetLineMaxHeight(const char* text,
1001                                         uint16_t lineLength,
1002                                         uint16_t fontId,
1003                                         uint8_t fontSize,
1004                                         uint16_t& letterIndex,
1005                                         SpannableString* spannableString)
1006 {
1007     if (!freeTypeInited_) {
1008         return INVALID_RET_VALUE;
1009     }
1010     uint32_t i = 0;
1011     uint16_t textNum = 0;
1012     uint16_t emojiNum = 0;
1013     uint16_t loopNum = 0;
1014     uint16_t maxHeight = GetHeight(fontId, fontSize);
1015     while (i < lineLength) {
1016         uint32_t unicode = TypedText::GetUTF8Next(text, i, i);
1017         TypedText::IsColourWord(unicode, fontId, fontSize) ? emojiNum++ : textNum++;
1018         loopNum++;
1019         if (spannableString != nullptr && spannableString->GetSpannable(letterIndex)) {
1020             int16_t spannableHeight = 0;
1021             spannableString->GetFontHeight(letterIndex, spannableHeight, fontId, fontSize);
1022             uint16_t tempHeight = static_cast<uint16_t>(spannableHeight);
1023             maxHeight = tempHeight > maxHeight ? tempHeight : maxHeight;
1024         }
1025         letterIndex++;
1026         if (i > 0 && ((text[i - 1] == '\r') || (text[i - 1] == '\n'))) {
1027             break;
1028         }
1029     }
1030     return GetMaxSubLineHeight(textNum, loopNum, maxHeight, emojiNum);
1031 }
1032 
GetMaxSubLineHeight(uint16_t textNum,uint16_t loopNum,uint16_t maxHeight,uint16_t emojiNum)1033 uint16_t UIFontVector::GetMaxSubLineHeight(uint16_t textNum, uint16_t loopNum, uint16_t maxHeight, uint16_t emojiNum)
1034 {
1035     // The number of words is the same as the number of cycles, which means that this line is all words
1036     if (textNum == loopNum) {
1037         for (uint8_t i = 0; i < currentFontInfoNum_; i++) {
1038             if (!IsEmojiFont(i)) {
1039                 uint16_t height = static_cast<uint16_t>(ftFaces_[i]->size->metrics.height / FONT_PIXEL_IN_POINT);
1040                 if (height > maxHeight) {
1041                     maxHeight = height;
1042                 }
1043                 return maxHeight;
1044             }
1045         }
1046     }
1047     // The number of emoji is the same as the number of cycles, indicating that this line is all emoji
1048     if (emojiNum == loopNum) {
1049         for (uint8_t i = 0; i < currentFontInfoNum_; i++) {
1050             if (IsEmojiFont(i)) {
1051                 return static_cast<uint16_t>(ftFaces_[i]->size->metrics.height / FONT_PIXEL_IN_POINT);
1052             }
1053         }
1054     }
1055     // A line has both emoji and words
1056     if ((textNum > 0) && (emojiNum > 0)) {
1057         for (uint8_t i = 0; i < currentFontInfoNum_; i++) {
1058             uint16_t tmpHeight = static_cast<uint16_t>(ftFaces_[i]->size->metrics.height / FONT_PIXEL_IN_POINT);
1059             maxHeight = tmpHeight > maxHeight ? tmpHeight : maxHeight;
1060         }
1061     }
1062     return maxHeight;
1063 }
1064 
SetPsramMemory(uintptr_t psramAddr,uint32_t psramLen)1065 void UIFontVector::SetPsramMemory(uintptr_t psramAddr, uint32_t psramLen)
1066 {
1067     BaseFont::SetPsramMemory(psramAddr, psramLen);
1068     FontRamAllocator::GetInstance().SetRamAddr(psramAddr, psramLen);
1069 }
1070 
SetCurrentLangId(uint8_t langId)1071 int8_t UIFontVector::SetCurrentLangId(uint8_t langId)
1072 {
1073     GRAPHIC_LOGE("UIFontVector::SetCurrentLangId start");
1074     FontRamAllocator::GetInstance().ClearRam();
1075 #if defined(ENABLE_SHAPING) && ENABLE_SHAPING
1076     UITextShaping::GetInstance()->ClearTtfHeader();
1077 #endif
1078     UIFontCacheManager* fontCacheManager = UIFontCacheManager::GetInstance();
1079     fontCacheManager->ClearCacheFlag();
1080     fontCacheManager->BitmapCacheClear();
1081 
1082     if (fontCacheManager->GlyphsCacheInit() != RET_VALUE_OK) {
1083         GRAPHIC_LOGE("UIFontCacheManager::GlyphsCacheInit init failed");
1084         return INVALID_RET_VALUE;
1085     }
1086 
1087     fontCacheManager->BitmapCacheInit();
1088     return RET_VALUE_OK;
1089 }
1090 } // namespace OHOS
1091