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_bitmap.h"
17
18#include "draw/draw_utils.h"
19#include "font/font_ram_allocator.h"
20#include "font/ui_font.h"
21#include "font/ui_font_adaptor.h"
22#include "font/ui_font_builder.h"
23#include "gfx_utils/file.h"
24#include "gfx_utils/graphic_log.h"
25#include "graphic_config.h"
26#if defined(ENABLE_MULTI_FONT) && ENABLE_MULTI_FONT
27#include "font/ui_multi_font_manager.h"
28#endif
29#if defined(ENABLE_SHAPING) && ENABLE_SHAPING
30#include "font/ui_text_shaping.h"
31#endif
32#include "font/ui_font_cache_manager.h"
33
34namespace OHOS {
35UIFontBitmap::UIFontBitmap() : offset_(0), dynamicFont_() {}
36
37UIFontBitmap::~UIFontBitmap()
38{
39    CloseFontFd();
40}
41
42void UIFontBitmap::CloseFontFd()
43{
44    for (uint16_t i = 0; i < dynamicFontFd_.Size(); i++) {
45        if (dynamicFontFd_[i] >= 0) {
46            close(dynamicFontFd_[i]);
47            dynamicFontFd_[i] = -1;
48        }
49    }
50}
51
52bool UIFontBitmap::IsVectorFont() const
53{
54    return false;
55}
56
57uint16_t
58    UIFontBitmap::GetShapingFontId(char* text, uint8_t& ttfId, uint32_t& script, uint16_t fontId, uint8_t size) const
59{
60#if defined(ENABLE_MULTI_FONT) && ENABLE_MULTI_FONT
61    return UIMultiFontManager::GetInstance()->GetShapingFontId(text, fontId, ttfId, script);
62#else
63    UITextLanguageFontParam* fontParam = UIFontBuilder::GetInstance()->GetTextLangFontsTable(fontId);
64    if (fontParam == nullptr) {
65        return 0;
66    }
67    ttfId = fontParam->ttfId;
68    return fontParam->shaping;
69#endif
70}
71
72uint8_t UIFontBitmap::GetFontWeight(uint16_t fontId)
73{
74    UITextLanguageFontParam* fontParam = UIFontBuilder::GetInstance()->GetTextLangFontsTable(fontId);
75    if (fontParam == nullptr) {
76        GRAPHIC_LOGE("UIFontBitmap::GetFontWeigh invalid fontId");
77        return 0;
78    }
79    return fontParam->fontWeight;
80}
81
82int8_t UIFontBitmap::SetFontPath(const char* path, FontType type)
83{
84    if ((path == nullptr) || (type != DYNAMIC_FONT)) {
85        GRAPHIC_LOGE("UIFontBitmap::SetFontPath invalid parameter");
86        return INVALID_RET_VALUE;
87    }
88#ifdef _WIN32
89    int32_t fontFd = open(path, O_RDONLY | O_BINARY);
90#else
91    int32_t fontFd = open(path, O_RDONLY);
92#endif
93    if (fontFd < 0) {
94        GRAPHIC_LOGE("UIFontBitmap::SetFontPath file Open failed");
95        return INVALID_RET_VALUE;
96    }
97
98    int32_t ret = dynamicFont_.SetFile(path, fontFd, offset_, GlyphCacheType::CACHE_TYPE_DYNAMIC);
99    if (ret == INVALID_RET_VALUE) {
100        GRAPHIC_LOGE("GlyphsManager::SetFile failed");
101        close(fontFd);
102        return ret;
103    }
104    dynamicFontFd_.PushBack(fontFd);
105    return RET_VALUE_OK;
106}
107
108uint16_t UIFontBitmap::GetHeight(uint16_t fontId, uint8_t fontSize)
109{
110    return dynamicFont_.GetFontHeight(fontId);
111}
112
113uint16_t UIFontBitmap::GetFontId(const char* ttfName, uint8_t size) const
114{
115    UIFontBuilder* fontBuilder = UIFontBuilder::GetInstance();
116    if (ttfName == nullptr) {
117        return fontBuilder->GetBitmapFontIdMax();
118    }
119    uint16_t id;
120    for (id = 0; id < fontBuilder->GetBitmapFontIdMax(); ++id) {
121        UITextLanguageFontParam* fontParam = fontBuilder->GetTextLangFontsTable(id);
122        if (fontParam != nullptr) {
123            if ((fontParam->size == size) && (strncmp(fontParam->ttfName, ttfName, TTF_NAME_LEN_MAX) == 0)) {
124                break;
125            }
126        }
127    }
128    return id;
129}
130
131int16_t UIFontBitmap::GetWidth(uint32_t unicode, uint16_t fontId, uint8_t fontSize)
132{
133    return GetWidthInFontId(unicode, fontId);
134}
135
136uint8_t* UIFontBitmap::GetBitmap(uint32_t unicode, GlyphNode& glyphNode, uint16_t fontId, uint8_t fontSize)
137{
138    return SearchInFont(unicode, glyphNode, fontId);
139}
140
141bool UIFontBitmap::IsEmojiFont(uint16_t fontId)
142{
143    return false;
144}
145
146int8_t UIFontBitmap::GetFontHeader(FontHeader& fontHeader, uint16_t fontId, uint8_t fontSize)
147{
148    const FontHeader* header = dynamicFont_.GetFontHeader(fontId);
149    if (header != nullptr) {
150        fontHeader = *header;
151        return RET_VALUE_OK;
152    }
153    return INVALID_RET_VALUE;
154}
155
156#if defined(ENABLE_MULTI_FONT) && ENABLE_MULTI_FONT
157int8_t UIFontBitmap::GetMultiGlyphNode(uint32_t unicode, GlyphNode& glyphNode, uint16_t fontId)
158{
159    int8_t ret = GetGlyphNode(unicode, glyphNode, fontId);
160    if (ret == RET_VALUE_OK) {
161        return ret;
162    }
163
164    uint16_t* searchLists = nullptr;
165    int8_t listSize = UIMultiFontManager::GetInstance()->GetSearchFontList(fontId, &searchLists);
166    int8_t currentIndex = 0;
167    if ((searchLists == nullptr) || (listSize == 0)) {
168        return INVALID_RET_VALUE;
169    }
170    do {
171        ret = GetGlyphNode(unicode, glyphNode, searchLists[currentIndex]);
172        if (ret != INVALID_RET_VALUE) {
173            return ret;
174        }
175        // switch to next search List
176        currentIndex++;
177    } while ((currentIndex < listSize) && (searchLists != nullptr));
178    return INVALID_RET_VALUE;
179}
180#endif
181
182int8_t UIFontBitmap::GetGlyphNode(uint32_t unicode, GlyphNode& glyphNode, uint16_t fontId, uint8_t fontSize)
183{
184    const GlyphNode* node = dynamicFont_.GetGlyphNode(unicode, fontId);
185    if (node != nullptr) {
186        glyphNode = *node;
187        return RET_VALUE_OK;
188    }
189    GRAPHIC_LOGE("UIFontBitmap::GetGlyphNode get glyphNode failed");
190    return INVALID_RET_VALUE;
191}
192
193int8_t UIFontBitmap::GetGlyphNodeFromFile(uint32_t unicode, GlyphNode& glyphNode, uint16_t fontId)
194{
195    const GlyphNode* node = dynamicFont_.GetGlyphNodeFromFiles(unicode, fontId);
196    if (node != nullptr) {
197        glyphNode = *node;
198        return RET_VALUE_OK;
199    }
200    return INVALID_RET_VALUE;
201}
202
203int8_t UIFontBitmap::GetFontVersion(FontType type, const char* path, char* version, uint8_t len)
204{
205    if (type != DYNAMIC_FONT) {
206        return INVALID_RET_VALUE;
207    }
208    return dynamicFont_.GetFontVersion(path, version, len);
209}
210
211int8_t UIFontBitmap::SetCurrentLangId(uint8_t langId)
212{
213    GRAPHIC_LOGE("UIFontBitmap::SetCurrentLangId start");
214    UIFontCacheManager* fontCacheManager = UIFontCacheManager::GetInstance();
215
216    if (fontCacheManager->GlyphsCacheInit() != RET_VALUE_OK) {
217        GRAPHIC_LOGE("UIFontCacheManager::GlyphsCacheInit init failed");
218        return INVALID_RET_VALUE;
219    }
220
221    fontCacheManager->BitmapCacheInit();
222    return RET_VALUE_OK;
223}
224
225UITextLanguageFontParam* UIFontBitmap::GetFontInfo(uint16_t fontId) const
226{
227    return UIFontBuilder::GetInstance()->GetTextLangFontsTable(fontId);
228}
229
230int8_t UIFontBitmap::GetDynamicFontBitmap(uint32_t unicode, BufferInfo& bufInfo, uint16_t fontId)
231{
232    return dynamicFont_.GetBitmap(unicode, bufInfo, fontId);
233}
234
235uint8_t* UIFontBitmap::GetCacheBitmap(uint16_t fontId, uint32_t unicode)
236{
237    TextStyle textStyle = TEXT_STYLE_NORMAL;
238    return UIFontCacheManager::GetInstance()->GetBitmap(fontId, unicode, textStyle);
239}
240
241void UIFontBitmap::PutCacheSpace(uint8_t* addr)
242{
243    UIFontCacheManager::GetInstance()->PutSpace(addr);
244}
245
246int16_t UIFontBitmap::GetDynamicFontWidth(uint32_t unicode, uint16_t fontId)
247{
248    return dynamicFont_.GetFontWidth(unicode, fontId);
249}
250
251uint8_t* UIFontBitmap::SearchInFont(uint32_t unicode, GlyphNode& glyphNode, uint16_t fontId)
252{
253    GraphicLockGuard guard(lock_);
254    UIFontCacheManager* fontCacheManager =  UIFontCacheManager::GetInstance();
255    if (fontCacheManager->GetBitmapCache() == nullptr) {
256        return nullptr;
257    }
258    if (!UIFontAdaptor::IsSameTTFId(fontId, unicode)) {
259        GRAPHIC_LOGE("UIFontBitmap::SearchInFont fontId and unicode not match");
260        return nullptr;
261    }
262    int8_t ret = GetGlyphNode(unicode, glyphNode, fontId);
263    if (ret != RET_VALUE_OK) {
264        return nullptr;
265    }
266    TextStyle textStyle = TEXT_STYLE_NORMAL;
267    uint8_t* bitmap = fontCacheManager->GetBitmap(fontId, unicode, textStyle);
268    if (bitmap != nullptr) {
269        if (glyphNode.dataFlag == glyphNode.fontId && fontId == glyphNode.fontId) {
270            return bitmap;
271        } else {
272            GRAPHIC_LOGE("DataFlag of bitmap node not equal to fontId.");
273        }
274    }
275    if (glyphNode.kernOff <= glyphNode.dataOff) {
276        return nullptr;
277    }
278    ColorMode mode = UIFont::GetInstance()->GetColorType(fontId);
279    BufferInfo bufInfo = UIFontAllocator::GetCacheBuffer(fontId, unicode, mode, glyphNode, false, textStyle);
280    ret = dynamicFont_.GetBitmap(unicode, bufInfo, fontId);
281    if (ret == RET_VALUE_OK) {
282        return reinterpret_cast<uint8_t*>(bufInfo.virAddr);
283    }
284    PutCacheSpace(reinterpret_cast<uint8_t*>(bufInfo.virAddr));
285    return nullptr;
286}
287
288int16_t UIFontBitmap::GetWidthInFontId(uint32_t unicode, uint16_t fontId)
289{
290    if (!UIFontAdaptor::IsSameTTFId(fontId, unicode)) {
291        GRAPHIC_LOGE("UIFontBitmap::GetWidthInFontId fontId and unicode not match");
292        return INVALID_RET_VALUE;
293    }
294    return GetDynamicFontWidth(unicode, fontId);
295}
296
297void UIFontBitmap::SetFontFileOffset(uint32_t offset)
298{
299    offset_ = offset;
300}
301
302uint16_t UIFontBitmap::GetOffsetPosY(const char* text,
303                                     uint16_t lineLength,
304                                     bool& isEmoijLarge,
305                                     uint16_t fontId,
306                                     uint8_t fontSize)
307{
308    uint32_t i = 0;
309    uint16_t textNum = 0;
310    uint16_t emojiNum = 0;
311
312    uint16_t loopNum = 0;
313    GlyphNode glyphNode;
314    GlyphNode emoijMaxNode = {};
315    uint8_t maxFontSie = fontSize;
316    while (i < lineLength) {
317        uint32_t unicode = TypedText::GetUTF8Next(text, i, i);
318#if defined(ENABLE_MULTI_FONT) && ENABLE_MULTI_FONT
319        uint8_t ret = GetMultiGlyphNode(unicode, glyphNode, fontId);
320#else
321        uint8_t ret = GetGlyphNode(unicode, glyphNode, fontId, fontSize);
322#endif
323        if (ret == RET_VALUE_OK) {
324            uint8_t weight = GetFontWeight(glyphNode.fontId);
325            if (weight >= 16) { // 16: bit rgb565 rgba8888
326                emoijMaxNode = glyphNode.rows > emoijMaxNode.rows ? glyphNode : emoijMaxNode;
327                emojiNum++;
328            } else {
329                textNum++;
330            }
331            loopNum++;
332        }
333    }
334    // The number of emoji is the same as the number of cycles, indicating that this line is all emoji
335    // The number of words is the same as the number of cycles, which means that this line is all words
336    if ((emojiNum == loopNum) || (textNum == loopNum)) {
337        isEmoijLarge = true;
338        return 0;
339    }
340    isEmoijLarge = emoijMaxNode.rows > maxFontSie;
341    uint16_t offset = 0;
342    if (isEmoijLarge) {
343        // If the emoji is higher than the text
344        if (emoijMaxNode.top >= maxFontSie) {
345            offset = emoijMaxNode.top - maxFontSie;
346        }
347    } else {
348        // If text are higher than emoji
349        if (maxFontSie >= emoijMaxNode.rows) {
350            // should top - ros.
351            offset = maxFontSie - emoijMaxNode.rows;
352        }
353    }
354    return offset;
355}
356
357uint16_t UIFontBitmap::GetLineMaxHeight(const char* text,
358                                        uint16_t lineLength,
359                                        uint16_t fontId,
360                                        uint8_t fontSize,
361                                        uint16_t& letterIndex,
362                                        SpannableString* spannableString)
363{
364    uint16_t maxHeight = GetHeight(fontId, fontSize);
365    if (spannableString == nullptr) {
366        return maxHeight;
367    }
368
369    uint32_t i = 0;
370    while (i < lineLength) {
371        TypedText::GetUTF8Next(text, i, i);
372        if (spannableString != nullptr && spannableString->GetSpannable(letterIndex)) {
373            int16_t spannableHeight = 0;
374            spannableString->GetFontHeight(letterIndex, spannableHeight, fontId, fontSize);
375            uint16_t tempHeight = static_cast<uint16_t>(spannableHeight);
376            maxHeight = tempHeight > maxHeight ? tempHeight : maxHeight;
377        }
378        letterIndex++;
379        if (i > 0 && ((text[i - 1] == '\r') || (text[i - 1] == '\n'))) {
380            break;
381        }
382    }
383
384    return maxHeight;
385}
386
387void UIFontBitmap::SetPsramMemory(uintptr_t psramAddr, uint32_t psramLen)
388{
389    BaseFont::SetPsramMemory(psramAddr, psramLen);
390    FontRamAllocator::GetInstance().SetRamAddr(psramAddr, psramLen);
391}
392} // namespace OHOS
393