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         close(fpTtf);
331         return false;
332     }
333     ttfHeader.len = static_cast<uint32_t>(headerLength);
334     if (ttfHeader.len > ttfBufferSize) {
335         close(fpTtf);
336         return false;
337     }
338     int32_t ret = lseek(fpTtf, 0, SEEK_SET);
339     if (ret != 0) {
340         close(fpTtf);
341         return false;
342     }
343     ret = read(fpTtf, reinterpret_cast<void*>(ttfBuffer), ttfHeader.len);
344     if (ret != headerLength) {
345         close(fpTtf);
346         return false;
347     }
348     close(fpTtf);
349     return true;
350 }
351 
352 struct TtcHeader {
353     uint32_t ttcTag;
354     uint16_t major;
355     uint16_t minor;
356     int32_t numFonts;
357 };
GetTtfInfoFromTtc(uint8_t* ttfBuffer, uint32_t ttfBufferSize, TtfHeader& ttfHeader, UITextLanguageFontParam fontInfo)358 bool UIFontVector::GetTtfInfoFromTtc(uint8_t* ttfBuffer,
359                                      uint32_t ttfBufferSize,
360                                      TtfHeader& ttfHeader,
361                                      UITextLanguageFontParam fontInfo)
362 {
363     if ((ttfBuffer == nullptr) || (ttfBufferSize == 0) || (fontInfo.ttcIndex >= FONT_TTC_MAX)) {
364         return false;
365     }
366     FT_Stream stream = ttcInfos_[fontInfo.ttcIndex].stream;
367     if (stream == nullptr) {
368         return false;
369     }
370 
371     FT_Error error = FT_Err_Ok;
372     if (FT_STREAM_SEEK(0)) {
373         return false;
374     }
375 
376     // read ttc header
377     TtcHeader header = {};
378     static const FT_Frame_Field ttcHeaderFields[] = {
379 #undef FT_STRUCTURE
380 #define FT_STRUCTURE TtcHeader
381         FT_FRAME_START(12), // 12: see ttc header
382         FT_FRAME_ULONG(ttcTag), FT_FRAME_LONG(numFonts), FT_FRAME_END};
383     if (FT_STREAM_READ_FIELDS(ttcHeaderFields, &header)) {
384         return false;
385     }
386 
387     // check if ttc file
388     if (header.ttcTag != TTAG_ttcf) { // 'ttcf' - TTC file
389         return false;
390     }
391 
392     uint8_t ttfIndex = fontInfo.ttfIndex;
393     if (ttfIndex >= header.numFonts) {
394         // invalid index
395         return false;
396     }
397 
398     // change position to the ttf offset
399     if (FT_STREAM_SKIP(4 * ttfIndex)) { // 4: table dictionary offset length
400         return false;
401     }
402 
403     // get the ttf length
404     uint32_t ttfOffset;
405     if (FT_READ_ULONG(ttfOffset)) {
406         return false;
407     }
408     uint32_t ttfLength = 0;
409     FT_ULong ttcLength = stream->size;
410     if (ttcLength < ttfOffset) {
411         return false;
412     }
413     if (ttfIndex + 1 == header.numFonts) {
414         ttfLength = ttcLength - ttfOffset;
415     } else {
416         uint32_t nextTtfOffset;
417         if (FT_READ_ULONG(nextTtfOffset)) {
418             return false;
419         }
420         ttfLength = nextTtfOffset - ttfOffset;
421     }
422     if (ttfLength > ttfBufferSize) {
423         return false;
424     }
425     if (FT_STREAM_SEEK(ttfOffset) || FT_STREAM_READ(ttfBuffer, ttfLength)) {
426         return false;
427     }
428     ttfHeader.len = ttfLength;
429 
430     // read number of tables
431     uint16_t numTables;
432     if (FT_STREAM_SEEK(ttfOffset + 4) || FT_READ_USHORT(numTables)) { // 4: sfntVersion length
433         return false;
434     }
435 
436     // change the offset of the ttf tableRecord compare with ttfOffset from ttc header
437     uint32_t* p = reinterpret_cast<uint32_t*>(ttfBuffer + 20); // 20: 12(TableDirectory) + 8(tableTag and checksum)
438     for (uint16_t i = 0; i < numTables; i++) {
439         p[0] = FT_PEEK_ULONG(p) - ttfOffset;
440         p[0] = FT_PEEK_ULONG(p);
441         p += 4; // 4: Table Record size
442     }
443     return true;
444 }
IsVectorFont() const445 bool UIFontVector::IsVectorFont() const
446 {
447     return true;
448 }
449 
GetFontWeight(uint16_t fontId)450 uint8_t UIFontVector::GetFontWeight(uint16_t fontId)
451 {
452     if (fontId >= FONT_ID_MAX) {
453         return BPP_BIT_8;
454     }
455 
456     return fontInfo_[fontId].fontWeight;
457 }
458 
SetFontPath(const char* path, FontType type)459 int8_t UIFontVector::SetFontPath(const char* path, FontType type)
460 {
461     if (path == nullptr) {
462         return INVALID_RET_VALUE;
463     }
464     ttfDir_ = path;
465     return RET_VALUE_OK;
466 }
467 
GetFaceInfo(uint16_t fontId, uint8_t fontSize, FaceInfo& faceInfo)468 int8_t UIFontVector::GetFaceInfo(uint16_t fontId, uint8_t fontSize, FaceInfo& faceInfo)
469 {
470     if ((fontId >= FONT_ID_MAX) || (fontSize == 0)) {
471         return INVALID_RET_VALUE;
472     }
473 
474     faceInfo.key = GetKey(fontId, fontSize);
475     faceInfo.face = ftFaces_[fontId];
476 
477     if (fontSize_[fontId] == fontSize) {
478         return RET_VALUE_OK;
479     }
480     const UITextLanguageFontParam* fontInfo = GetFontInfo(fontId);
481     if ((fontInfo == nullptr) || (fontInfo->ttfName == nullptr)) {
482         return INVALID_RET_VALUE;
483     }
484 
485     if (!freeTypeInited_) {
486         return INVALID_RET_VALUE;
487     }
488 
489     // Set the size
490     int8_t ret;
491     if (IsEmojiFont(fontId)) {
492         ret = SetupColorFont(ftFaces_[fontId], fontSize);
493     } else {
494         ret = FT_Set_Char_Size(faceInfo.face, fontSize * FONT_PIXEL_IN_POINT, 0, 0, 0);
495     }
496 
497     if (ret != 0) {
498         return INVALID_RET_VALUE;
499     }
500     fontSize_[fontId] = fontSize;
501     return RET_VALUE_OK;
502 }
503 
GetHeight(uint16_t fontId, uint8_t fontSize)504 uint16_t UIFontVector::GetHeight(uint16_t fontId, uint8_t fontSize)
505 {
506     FaceInfo faceInfo;
507     int8_t ret = GetFaceInfo(fontId, fontSize, faceInfo);
508     if (ret != RET_VALUE_OK) {
509         return INVALID_RET_VALUE;
510     }
511     if (!freeTypeInited_ || (faceInfo.face == nullptr)) {
512         return 0;
513     }
514     return static_cast<uint16_t>(faceInfo.face->size->metrics.height / FONT_PIXEL_IN_POINT);
515 }
516 
517 uint16_t
GetShapingFontId(char* text, uint8_t& ttfId, uint32_t& script, uint16_t fontId, uint8_t size) const518     UIFontVector::GetShapingFontId(char* text, uint8_t& ttfId, uint32_t& script, uint16_t fontId, uint8_t size) const
519 {
520 #if defined(ENABLE_MULTI_FONT) && ENABLE_MULTI_FONT
521     const UITextLanguageFontParam* fontParam1 = GetFontInfo(fontId);
522     if (fontParam1 == nullptr) {
523         return 0;
524     }
525     if (fontParam1->shaping == 0) {
526         UIMultiFontManager* multiFontManager = UIMultiFontManager::GetInstance();
527         if (!multiFontManager->IsNeedShaping(text, ttfId, script)) {
528             return 0; // 0 means  no need to shape
529         }
530         uint16_t* searchLists = nullptr;
531         int8_t length = multiFontManager->GetSearchFontList(fontId, &searchLists);
532         const UITextLanguageFontParam* fontParam2 = nullptr;
533         for (uint8_t i = 0; i < length; i++) {
534             fontParam2 = GetFontInfo(searchLists[i]);
535             if (fontParam2 == nullptr) {
536                 continue;
537             }
538             if (fontParam2->ttfId == ttfId) {
539                 return fontParam2->shaping;
540             }
541         }
542         return 0;
543     }
544     ttfId = fontParam1->ttfId;
545 
546 #if defined(ENABLE_SHAPING) && ENABLE_SHAPING
547     script = UIMultiFontManager::GetInstance()->GetScriptByTtfId(ttfId);
548 #endif
549     return fontParam1->shaping;
550 #else
551     const UITextLanguageFontParam* fontInfo = GetFontInfo(fontId);
552     if (fontInfo == nullptr) {
553         return 0;
554     }
555     ttfId = fontInfo->ttfId;
556     return fontInfo->shaping;
557 #endif
558 }
559 
GetFontId(const char* ttfName, uint8_t fontSize) const560 uint16_t UIFontVector::GetFontId(const char* ttfName, uint8_t fontSize) const
561 {
562     if (ttfName != nullptr) {
563         int32_t i = 0;
564         while (i < FONT_ID_MAX) {
565             if ((fontInfo_[i].ttfName != nullptr) && (strstr(fontInfo_[i].ttfName, ttfName) != nullptr)) {
566                 return static_cast<uint16_t>(i);
567             }
568             i++;
569         }
570     }
571 
572     return static_cast<uint16_t>(FONT_ID_MAX);
573 }
574 
GetFontId(uint32_t unicode) const575 uint16_t UIFontVector::GetFontId(uint32_t unicode) const
576 {
577     int32_t i = 0;
578     uint8_t ttfId = ((unicode >> 24) & 0x1F); // 24: Whether 25 ~29 bit storage is ttfId 0x1F:5bit
579     while (i < FONT_ID_MAX) {
580         if (fontInfo_[i].ttfName == nullptr) {
581             i++;
582             continue;
583         }
584         if (fontInfo_[i].ttfId == ttfId) {
585             return i;
586         }
587         i++;
588     }
589     return FONT_INVALID_TTF_ID;
590 }
591 
GetWidth(uint32_t unicode, uint16_t fontId, uint8_t fontSize)592 int16_t UIFontVector::GetWidth(uint32_t unicode, uint16_t fontId, uint8_t fontSize)
593 {
594     if ((fontId >= FONT_ID_MAX) || (fontSize == 0)) {
595         return INVALID_RET_VALUE;
596     }
597 
598     GlyphNode node;
599     int8_t ret = GetGlyphNode(unicode, node, fontId, fontSize);
600     if (ret != RET_VALUE_OK) {
601         return INVALID_RET_VALUE;
602     }
603     return node.advance;
604 }
605 
GetFontHeader(FontHeader& fontHeader, uint16_t fontId, uint8_t fontSize)606 int8_t UIFontVector::GetFontHeader(FontHeader& fontHeader, uint16_t fontId, uint8_t fontSize)
607 {
608     FaceInfo faceInfo;
609     int8_t ret = GetFaceInfo(fontId, fontSize, faceInfo);
610     if (ret != RET_VALUE_OK) {
611         return INVALID_RET_VALUE;
612     }
613     if (!freeTypeInited_ || (faceInfo.face == nullptr)) {
614         return INVALID_RET_VALUE;
615     }
616 
617     fontHeader.ascender = static_cast<int16_t>(faceInfo.face->size->metrics.ascender / FONT_PIXEL_IN_POINT);
618     fontHeader.descender = static_cast<int16_t>(faceInfo.face->size->metrics.descender / FONT_PIXEL_IN_POINT);
619     fontHeader.fontHeight = static_cast<uint16_t>(faceInfo.face->size->metrics.height / FONT_PIXEL_IN_POINT);
620     return RET_VALUE_OK;
621 }
622 
SaveGlyphNode(uint32_t unicode, uint16_t fontKey, Metric *metric)623 void UIFontVector::SaveGlyphNode(uint32_t unicode, uint16_t fontKey, Metric *metric)
624 {
625     GlyphCacheNode* node = UIFontCacheManager::GetInstance()->GetNodeCacheSpace(unicode, fontKey);
626     if (node == nullptr) {
627         return;
628     }
629     node->node.left = metric->left;
630     node->node.top = metric->top;
631     node->node.cols = metric->cols;
632     node->node.rows = metric->rows;
633     node->node.advance = metric->advance;
634     node->node.unicode = unicode;
635     node->node.fontId = fontKey;
636 }
637 
GetGlyphNode(uint32_t unicode, GlyphNode& glyphNode, uint16_t fontId, uint8_t fontSize)638 int8_t UIFontVector::GetGlyphNode(uint32_t unicode, GlyphNode& glyphNode, uint16_t fontId, uint8_t fontSize)
639 {
640     // get glyph from glyph cache
641     uint16_t fontKey = GetKey(fontId, fontSize);
642     UIFontCacheManager* fontCacheManager = UIFontCacheManager::GetInstance();
643     GlyphCacheNode* cacheNode = fontCacheManager->GetNodeFromCache(unicode, fontKey, GlyphCacheType::CACHE_TYPE_NONE);
644     if (cacheNode != nullptr) {
645         glyphNode = cacheNode->node;
646         return RET_VALUE_OK;
647     }
648 
649 #if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
650     uint8_t* bitmap = fontCacheManager->GetBitmap(fontKey, unicode, glyphNode.textStyle);
651 #else
652     uint8_t* bitmap = fontCacheManager->GetBitmap(fontKey, unicode, TEXT_STYLE_NORMAL);
653 #endif
654     if (bitmap != nullptr) {
655         Metric* f = reinterpret_cast<Metric*>(bitmap);
656         glyphNode.left = f->left;
657         glyphNode.top = f->top;
658         glyphNode.cols = f->cols;
659         glyphNode.rows = f->rows;
660         glyphNode.advance = f->advance;
661         glyphNode.fontId = fontId;
662 
663         SaveGlyphNode(unicode, fontKey, f);
664         return RET_VALUE_OK;
665     }
666 
667     FaceInfo faceInfo;
668     int8_t ret = GetFaceInfo(fontId, fontSize, faceInfo);
669     if (ret != RET_VALUE_OK) {
670         return INVALID_RET_VALUE;
671     }
672     if (faceInfo.face == nullptr) {
673         return INVALID_RET_VALUE;
674     }
675 
676     int8_t error = LoadGlyphIntoFace(fontId, fontSize, unicode, glyphNode);
677     if (error != RET_VALUE_OK) {
678         return INVALID_RET_VALUE;
679     }
680 
681     return RET_VALUE_OK;
682 }
683 
GetBitmap(uint32_t unicode, GlyphNode& glyphNode, uint16_t fontId, uint8_t fontSize)684 uint8_t* UIFontVector::GetBitmap(uint32_t unicode, GlyphNode& glyphNode, uint16_t fontId, uint8_t fontSize)
685 {
686     uint16_t fontKey = GetKey(fontId, fontSize);
687     UIFontCacheManager* fontCacheManager = UIFontCacheManager::GetInstance();
688 #if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
689     uint8_t* bitmap = fontCacheManager->GetBitmap(fontKey, unicode, glyphNode.textStyle);
690 #else
691     uint8_t* bitmap = fontCacheManager->GetBitmap(fontKey, unicode, TEXT_STYLE_NORMAL);
692 #endif
693     if (bitmap != nullptr) {
694         Metric* f = reinterpret_cast<Metric*>(bitmap);
695         glyphNode.left = f->left;
696         glyphNode.top = f->top;
697         glyphNode.cols = f->cols;
698         glyphNode.rows = f->rows;
699         glyphNode.advance = f->advance;
700         glyphNode.fontId = fontId;
701         SaveGlyphNode(unicode, fontKey, f);
702         return bitmap + sizeof(Metric);
703     }
704     FaceInfo faceInfo;
705     int8_t ret = GetFaceInfo(fontId, fontSize, faceInfo);
706     if (ret != RET_VALUE_OK) {
707         return nullptr;
708     }
709     if (faceInfo.face == nullptr) {
710         return nullptr;
711     }
712 
713     int8_t error = LoadGlyphIntoFace(fontId, fontSize, unicode, glyphNode);
714     if (error != RET_VALUE_OK) {
715         return nullptr;
716     }
717 
718 #if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
719     bitmap = fontCacheManager->GetBitmap(fontKey, unicode, glyphNode.textStyle);
720 #else
721     bitmap = fontCacheManager->GetBitmap(fontKey, unicode, TEXT_STYLE_NORMAL);
722 #endif
723     if (bitmap != nullptr) {
724         return bitmap + sizeof(Metric);
725     } else {
726         return nullptr;
727     }
728 }
729 
IsEmojiFont(uint16_t fontId)730 bool UIFontVector::IsEmojiFont(uint16_t fontId)
731 {
732     if (fontId >= FONT_ID_MAX) {
733         return false;
734     }
735     return (fontInfo_[fontId].fontWeight >= 16); // 16: rgb color font
736 }
737 
738 #if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
SetItaly(FT_GlyphSlot slot)739 void UIFontVector::SetItaly(FT_GlyphSlot slot)
740 {
741     if (slot->format != FT_GLYPH_FORMAT_OUTLINE) {
742         GRAPHIC_LOGE("SetItaly error");
743         return;
744     }
745     float lean = 0.2f; // Slope of word
746     FT_Matrix matrix;
747     matrix.xx = 0x10000L; // Staggered matrix along x-axis
748     matrix.xy = lean * 0x10000L;
749     matrix.yx = 0;
750     matrix.yy = 0x10000L; // Staggered matrix along y-axis
751     FT_Outline outline = slot->outline;
752     FT_Outline_Transform(&outline, &matrix);
753 }
754 #endif
755 
756 #if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
SetBold(uint16_t fontId)757 void UIFontVector::SetBold(uint16_t fontId)
758 {
759     int32_t error;
760     FT_GlyphSlot slot = ftFaces_[fontId]->glyph;
761     // some reasonable strength, copied from freeType
762     FT_Pos xBold = FT_MulFix(ftFaces_[fontId]->units_per_EM, ftFaces_[fontId]->size->metrics.y_scale) / 24;
763     FT_Pos yBold = xBold;
764     if (ftFaces_[fontId]->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
765         FT_BBox oldBox;
766         FT_Outline_Get_CBox(&slot->outline, &oldBox);
767         error = FT_Outline_Embolden(&slot->outline, xBold);
768         if (error != 0) {
769             GRAPHIC_LOGE("SetBold error");
770             return;
771         }
772     } else if (ftFaces_[fontId]->glyph->format == FT_GLYPH_FORMAT_BITMAP) {
773         FT_Library ftLibrary = slot->library;
774         error = FT_Bitmap_Embolden(ftLibrary, &slot->bitmap, xBold, yBold);
775         if (error != 0) {
776             GRAPHIC_LOGE("SetBold error");
777             return;
778         }
779     }
780 }
781 #endif
782 
LoadGlyphIntoFace(uint16_t& fontId, uint8_t fontSize, uint32_t unicode, GlyphNode& glyphNode)783 int8_t UIFontVector::LoadGlyphIntoFace(uint16_t& fontId, uint8_t fontSize, uint32_t unicode, GlyphNode& glyphNode)
784 {
785     int32_t error;
786     if (IsGlyphFont(unicode) != 0) {
787         if (fontId >= FONT_ID_MAX || fontId != GetFontId(unicode)) {
788             return INVALID_RET_VALUE;
789         }
790         error = FT_Load_Glyph(ftFaces_[fontId], unicode & (0xFFFFFF), FT_LOAD_RENDER);
791     } else {
792         if (IsEmojiFont(fontId)) {
793             error = FT_Load_Char(ftFaces_[fontId], unicode, FT_LOAD_COLOR);
794         } else {
795             error = FT_Load_Char(ftFaces_[fontId], unicode, FT_LOAD_RENDER);
796         }
797     }
798     if ((error != 0) || (ftFaces_[fontId]->glyph->glyph_index == 0)) {
799         return INVALID_RET_VALUE;
800     }
801 
802     FaceInfo faceInfo;
803     faceInfo.key = GetKey(fontId, fontSize);
804     faceInfo.face = ftFaces_[fontId];
805 
806     glyphNode.left = faceInfo.face->glyph->bitmap_left;
807     glyphNode.top = faceInfo.face->glyph->bitmap_top;
808     glyphNode.cols = faceInfo.face->glyph->bitmap.width;
809     glyphNode.rows = faceInfo.face->glyph->bitmap.rows;
810     glyphNode.advance = static_cast<uint16_t>(faceInfo.face->glyph->advance.x / FONT_PIXEL_IN_POINT);
811     glyphNode.fontId = fontId;
812 
813 #if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
814     SetFace(faceInfo, unicode, glyphNode.textStyle);
815 #else
816     SetFace(faceInfo, unicode);
817 #endif
818     return RET_VALUE_OK;
819 }
820 
821 #if defined(ENABLE_TEXT_STYLE) && ENABLE_TEXT_STYLE
LoadGlyphIntoFace(uint16_t& fontId, uint32_t unicode, FT_Face face, TextStyle textStyle)822 int8_t UIFontVector::LoadGlyphIntoFace(uint16_t& fontId, uint32_t unicode, FT_Face face, TextStyle textStyle)
823 {
824     int32_t error;
825     if (IsGlyphFont(unicode) != 0) {
826         if (fontId != GetFontId(unicode)) {
827             return INVALID_RET_VALUE;
828         }
829         unicode = unicode & (0xFFFFFF); // Whether 0 ~24 bit storage is unicode
830         error = FT_Load_Glyph(ftFaces_[fontId], unicode, FT_LOAD_RENDER);
831     } else {
832         if (IsEmojiFont(fontId)) {
833             error = FT_Load_Char(ftFaces_[fontId], unicode, FT_LOAD_COLOR);
834         } else {
835             error = FT_Load_Char(ftFaces_[fontId], unicode, FT_LOAD_RENDER);
836         }
837     }
838     if ((error != 0) || (ftFaces_[fontId]->glyph->glyph_index == 0)) {
839         return INVALID_RET_VALUE;
840     }
841     if (textStyle == TEXT_STYLE_ITALIC) {
842         SetItaly(ftFaces_[fontId]->glyph);
843     } else if (textStyle == TEXT_STYLE_BOLD) {
844         SetBold(fontId);
845     } else if (textStyle == TEXT_STYLE_BOLD_ITALIC) {
846         SetItaly(ftFaces_[fontId]->glyph);
847         SetBold(fontId);
848     }
849     if (ftFaces_[fontId]->glyph->format != FT_GLYPH_FORMAT_BITMAP) {
850         error = FT_Render_Glyph(ftFaces_[fontId]->glyph, FT_RENDER_MODE_NORMAL);
851     }
852     if ((error != 0) || (ftFaces_[fontId]->glyph->glyph_index == 0)) {
853         return INVALID_RET_VALUE;
854     }
855     return RET_VALUE_OK;
856 }
857 #endif
858 
IsGlyphFont(uint32_t unicode)859 uint8_t UIFontVector::IsGlyphFont(uint32_t unicode)
860 {
861     uint16_t unicodeFontId = GetFontId(unicode);
862     if (unicodeFontId == FONT_INVALID_TTF_ID) {
863         return 0;
864     } else {
865         return fontInfo_[unicodeFontId].shaping;
866     }
867 }
868 
SetFace(FaceInfo& faceInfo, uint32_t unicode)869 void UIFontVector::SetFace(FaceInfo& faceInfo, uint32_t unicode)
870 {
871     SetFace(faceInfo, unicode, TEXT_STYLE_NORMAL);
872 }
873 
SetFace(FaceInfo& faceInfo, uint32_t unicode, TextStyle textStyle)874 void UIFontVector::SetFace(FaceInfo& faceInfo, uint32_t unicode, TextStyle textStyle)
875 {
876     Metric* f = reinterpret_cast<Metric*>(UIMalloc(sizeof(Metric)));
877     if (f == nullptr) {
878         return;
879     }
880     f->advance = static_cast<uint16_t>(faceInfo.face->glyph->advance.x / FONT_PIXEL_IN_POINT);
881     f->left = faceInfo.face->glyph->bitmap_left;
882     f->top = faceInfo.face->glyph->bitmap_top;
883     f->cols = faceInfo.face->glyph->bitmap.width;
884     f->rows = faceInfo.face->glyph->bitmap.rows;
885 
886     // cache glyph
887     SaveGlyphNode(unicode, faceInfo.key, f);
888 
889     int16_t pixSize;
890     ColorMode mode;
891     if (faceInfo.face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
892         pixSize = 0x04; // 4 Byte
893         mode = ARGB8888;
894     } else {
895         pixSize = 1;
896         mode = A8;
897     }
898 
899     GlyphNode glyphNode;
900     glyphNode.left = f->left;
901     glyphNode.top = f->top;
902     glyphNode.cols = f->cols;
903     glyphNode.rows = f->rows;
904     glyphNode.advance = f->advance;
905     glyphNode.unicode = unicode;
906     glyphNode.fontId = faceInfo.key;
907     BufferInfo bufInfo = UIFontAllocator::GetCacheBuffer(faceInfo.key, unicode, mode, glyphNode, true, textStyle);
908     uint32_t bitmapSize = bufInfo.stride * bufInfo.height;
909     uint32_t rawSize = glyphNode.cols * glyphNode.rows * pixSize;
910 
911     if (bufInfo.virAddr != nullptr) {
912         if (memcpy_s(bufInfo.virAddr, sizeof(Metric), f, sizeof(Metric)) != EOK) {
913             UIFontCacheManager::GetInstance()->PutSpace(reinterpret_cast<uint8_t*>(bufInfo.virAddr));
914             UIFree(f);
915             return;
916         }
917         if ((faceInfo.face->glyph->bitmap.buffer != nullptr) &&
918             (memcpy_s(reinterpret_cast<uint8_t*>(bufInfo.virAddr) + sizeof(Metric), bitmapSize,
919                       faceInfo.face->glyph->bitmap.buffer, rawSize) != EOK)) {
920             UIFontCacheManager::GetInstance()->PutSpace(reinterpret_cast<uint8_t*>(bufInfo.virAddr));
921             UIFree(f);
922             return;
923         }
924         UIFontAllocator::RearrangeBitmap(bufInfo, rawSize, true);
925         ClearFontGlyph(faceInfo.face);
926     }
927     UIFree(f);
928 }
929 
ClearFontGlyph(FT_Face face)930 void UIFontVector::ClearFontGlyph(FT_Face face)
931 {
932     if ((face != nullptr) && (face->glyph != nullptr)) {
933         // free unicode buffer immediately to save memory in multi font file load
934         // if not, it will be freed in next glyph load
935         ft_glyphslot_free_bitmap(face->glyph);
936         FT_Outline_Done(face->glyph->library, &face->glyph->outline);
937         if (face->glyph->internal != nullptr) {
938             FT_GlyphLoader_Reset(face->glyph->internal->loader);
939         }
940     }
941 }
942 
GetKey(uint16_t fontId, uint8_t size)943 inline uint16_t UIFontVector::GetKey(uint16_t fontId, uint8_t size)
944 {
945     return ((static_cast<uint16_t>(fontId)) << 8) + size; // fontId store at the (8+1)th bit
946 }
947 
GetOffsetPosY(const char* text, uint16_t lineLength, bool& isEmojiLarge, uint16_t fontId, uint8_t fontSize)948 uint16_t UIFontVector::GetOffsetPosY(const char* text,
949                                      uint16_t lineLength,
950                                      bool& isEmojiLarge,
951                                      uint16_t fontId,
952                                      uint8_t fontSize)
953 {
954     if (!freeTypeInited_) {
955         return INVALID_RET_VALUE;
956     }
957     uint32_t i = 0;
958     uint16_t textNum = 0;
959     uint16_t emojiNum = 0;
960     uint16_t loopNum = 0;
961     GlyphNode glyphNode;
962     GlyphNode emojiMaxNode = {};
963     uint8_t maxFontSize = fontSize;
964     while (i < lineLength) {
965         uint32_t unicode = TypedText::GetUTF8Next(text, i, i);
966         uint8_t ret = GetGlyphNode(unicode, glyphNode, fontId, fontSize);
967         if (ret == RET_VALUE_OK) {
968             uint8_t weight = GetFontWeight(glyphNode.fontId);
969             // 16: bit rgb565 rgba8888
970             if (weight >= 16) {
971                 emojiMaxNode = glyphNode.rows > emojiMaxNode.rows ? glyphNode : emojiMaxNode;
972                 emojiNum++;
973             } else {
974                 textNum++;
975             }
976             loopNum++;
977         }
978     }
979     // The number of emoji is the same as the number of cycles, indicating that this line is all emoji
980     // The number of words is the same as the number of cycles, which means that this line is all words
981     if ((emojiNum == loopNum) || (textNum == loopNum)) {
982         isEmojiLarge = true;
983         return 0;
984     }
985     isEmojiLarge = emojiMaxNode.rows > maxFontSize;
986     uint16_t offset = 0;
987     if (isEmojiLarge) {
988         // If the emoji is higher than the text
989         if (emojiMaxNode.top >= maxFontSize) {
990             offset = emojiMaxNode.top - maxFontSize;
991         }
992     } else {
993         // If text are higher than emoji
994         if (maxFontSize >= emojiMaxNode.rows) {
995             offset = maxFontSize - emojiMaxNode.rows;
996         }
997     }
998     return offset;
999 }
1000 
GetLineMaxHeight(const char* text, uint16_t lineLength, uint16_t fontId, uint8_t fontSize, uint16_t& letterIndex, SpannableString* spannableString)1001 uint16_t UIFontVector::GetLineMaxHeight(const char* text,
1002                                         uint16_t lineLength,
1003                                         uint16_t fontId,
1004                                         uint8_t fontSize,
1005                                         uint16_t& letterIndex,
1006                                         SpannableString* spannableString)
1007 {
1008     if (!freeTypeInited_) {
1009         return INVALID_RET_VALUE;
1010     }
1011     uint32_t i = 0;
1012     uint16_t textNum = 0;
1013     uint16_t emojiNum = 0;
1014     uint16_t loopNum = 0;
1015     uint16_t maxHeight = GetHeight(fontId, fontSize);
1016     while (i < lineLength) {
1017         uint32_t unicode = TypedText::GetUTF8Next(text, i, i);
1018         TypedText::IsColourWord(unicode, fontId, fontSize) ? emojiNum++ : textNum++;
1019         loopNum++;
1020         if (spannableString != nullptr && spannableString->GetSpannable(letterIndex)) {
1021             int16_t spannableHeight = 0;
1022             spannableString->GetFontHeight(letterIndex, spannableHeight, fontId, fontSize);
1023             uint16_t tempHeight = static_cast<uint16_t>(spannableHeight);
1024             maxHeight = tempHeight > maxHeight ? tempHeight : maxHeight;
1025         }
1026         letterIndex++;
1027         if (i > 0 && ((text[i - 1] == '\r') || (text[i - 1] == '\n'))) {
1028             break;
1029         }
1030     }
1031     return GetMaxSubLineHeight(textNum, loopNum, maxHeight, emojiNum);
1032 }
1033 
GetMaxSubLineHeight(uint16_t textNum, uint16_t loopNum, uint16_t maxHeight, uint16_t emojiNum)1034 uint16_t UIFontVector::GetMaxSubLineHeight(uint16_t textNum, uint16_t loopNum, uint16_t maxHeight, uint16_t emojiNum)
1035 {
1036     // The number of words is the same as the number of cycles, which means that this line is all words
1037     if (textNum == loopNum) {
1038         for (uint8_t i = 0; i < currentFontInfoNum_; i++) {
1039             if (!IsEmojiFont(i)) {
1040                 uint16_t height = static_cast<uint16_t>(ftFaces_[i]->size->metrics.height / FONT_PIXEL_IN_POINT);
1041                 if (height > maxHeight) {
1042                     maxHeight = height;
1043                 }
1044                 return maxHeight;
1045             }
1046         }
1047     }
1048     // The number of emoji is the same as the number of cycles, indicating that this line is all emoji
1049     if (emojiNum == loopNum) {
1050         for (uint8_t i = 0; i < currentFontInfoNum_; i++) {
1051             if (IsEmojiFont(i)) {
1052                 return static_cast<uint16_t>(ftFaces_[i]->size->metrics.height / FONT_PIXEL_IN_POINT);
1053             }
1054         }
1055     }
1056     // A line has both emoji and words
1057     if ((textNum > 0) && (emojiNum > 0)) {
1058         for (uint8_t i = 0; i < currentFontInfoNum_; i++) {
1059             uint16_t tmpHeight = static_cast<uint16_t>(ftFaces_[i]->size->metrics.height / FONT_PIXEL_IN_POINT);
1060             maxHeight = tmpHeight > maxHeight ? tmpHeight : maxHeight;
1061         }
1062     }
1063     return maxHeight;
1064 }
1065 
SetPsramMemory(uintptr_t psramAddr, uint32_t psramLen)1066 void UIFontVector::SetPsramMemory(uintptr_t psramAddr, uint32_t psramLen)
1067 {
1068     BaseFont::SetPsramMemory(psramAddr, psramLen);
1069     FontRamAllocator::GetInstance().SetRamAddr(psramAddr, psramLen);
1070 }
1071 
SetCurrentLangId(uint8_t langId)1072 int8_t UIFontVector::SetCurrentLangId(uint8_t langId)
1073 {
1074     GRAPHIC_LOGE("UIFontVector::SetCurrentLangId start");
1075     FontRamAllocator::GetInstance().ClearRam();
1076 #if defined(ENABLE_SHAPING) && ENABLE_SHAPING
1077     UITextShaping::GetInstance()->ClearTtfHeader();
1078 #endif
1079     UIFontCacheManager* fontCacheManager = UIFontCacheManager::GetInstance();
1080     fontCacheManager->ClearCacheFlag();
1081     fontCacheManager->BitmapCacheClear();
1082 
1083     if (fontCacheManager->GlyphsCacheInit() != RET_VALUE_OK) {
1084         GRAPHIC_LOGE("UIFontCacheManager::GlyphsCacheInit init failed");
1085         return INVALID_RET_VALUE;
1086     }
1087 
1088     fontCacheManager->BitmapCacheInit();
1089     return RET_VALUE_OK;
1090 }
1091 } // namespace OHOS
1092