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