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