1 /*
2 * Copyright (c) 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/glyphs_file.h"
17 #include "draw/draw_utils.h"
18 #include "font/font_ram_allocator.h"
19 #include "font/ui_font_builder.h"
20 #include "gfx_utils/file.h"
21 #include "gfx_utils/graphic_log.h"
22 #include "securec.h"
23
24 namespace OHOS {
GlyphsFile()25 GlyphsFile::GlyphsFile()
26 : binHeader_{{0}},
27 start_(0),
28 fontHeaderSectionStart_(0),
29 fontIndexSectionStart_(0),
30 glyphNodeSectionStart_(0),
31 bitMapSectionStart_(0),
32 fontHeaderCache_(nullptr),
33 indexCache_(nullptr),
34 fontName_(nullptr),
35 fp_(-1),
36 isFileSet_(false),
37 fontNum_(0)
38 {
39 }
~GlyphsFile()40 GlyphsFile::~GlyphsFile()
41 {
42 if (fontName_) {
43 UIFree(fontName_);
44 fontName_ = nullptr;
45 }
46 }
47
CacheInit()48 int8_t GlyphsFile::CacheInit()
49 {
50 uint32_t size = 0;
51 for (int32_t i = 0; i < fontNum_; i++) {
52 size += fontHeaderCache_[i].indexLen;
53 }
54
55 indexCache_ = reinterpret_cast<uint8_t*>(FontRamAllocator::GetInstance().Allocate(size));
56 if (indexCache_ == nullptr) {
57 GRAPHIC_LOGE("GlyphsFile::CacheInit Allocate failed");
58 return INVALID_RET_VALUE;
59 }
60
61 int32_t ret = read(fp_, indexCache_, size);
62 if (ret != static_cast<int32_t>(size)) {
63 GRAPHIC_LOGE("GlyphsFile::CacheInit read failed");
64 return INVALID_RET_VALUE;
65 }
66
67 return RET_VALUE_OK;
68 }
69
GetNodeFromFile(uint32_t unicode,uint16_t fontId,GlyphNode & node)70 int8_t GlyphsFile::GetNodeFromFile(uint32_t unicode, uint16_t fontId, GlyphNode& node)
71 {
72 uint16_t idx = 0;
73 uint32_t offset;
74 GlyphInfo glyphInfo;
75 int8_t result = GetGlyphInfo(fontId, glyphInfo);
76 if (result != RET_VALUE_OK) {
77 return INVALID_RET_VALUE;
78 }
79 for (int32_t i = RADIX_SHIFT_START; i >= 0; i -= RADIX_TREE_BITS) {
80 offset = idx * sizeof(IndexNode);
81 uint8_t key = static_cast<uint8_t>((unicode >> static_cast<uint8_t>(i)) & RADIX_TREE_MASK);
82 offset += key * sizeof(uint16_t);
83 idx = *(reinterpret_cast<uint16_t*>(glyphInfo.indexCache + offset));
84 if (idx == 0) {
85 return INVALID_RET_VALUE;
86 }
87 }
88
89 offset = glyphInfo.glyphNodeSectionStart + (idx - 1) * sizeof(GlyphNode);
90 int32_t ret = lseek(fp_, offset, SEEK_SET);
91 if (ret != static_cast<int32_t>(offset)) {
92 GRAPHIC_LOGE("GlyphsFile::GetNodeFromFile lseek failed");
93 return INVALID_RET_VALUE;
94 }
95
96 ret = read(fp_, &node, sizeof(GlyphNode));
97 if (ret < 0) {
98 GRAPHIC_LOGE("GlyphsFile::GetNodeFromFile read failed");
99 return INVALID_RET_VALUE;
100 }
101
102 return RET_VALUE_OK;
103 }
104
SetFontName(const char * fontName)105 void GlyphsFile::SetFontName(const char* fontName)
106 {
107 if (fontName_ != nullptr) {
108 return;
109 }
110
111 if (fontName == nullptr) {
112 GRAPHIC_LOGE("GlyphsFile::SetFontName invalid parameters");
113 return;
114 }
115
116 uint32_t nameLen = strlen(fontName);
117 if (nameLen > FONT_NAME_LEN_MAX) {
118 nameLen = FONT_NAME_LEN_MAX;
119 } else if (nameLen == 0) {
120 return;
121 }
122
123 fontName_ = static_cast<char*>(UIMalloc(++nameLen));
124 if (fontName_ == nullptr) {
125 return;
126 }
127 if (memcpy_s(fontName_, nameLen, fontName, nameLen) != EOK) {
128 UIFree(fontName_);
129 fontName_ = nullptr;
130 }
131 }
132
SetFile(const char * fontName,int32_t fp,uint32_t start)133 int8_t GlyphsFile::SetFile(const char* fontName, int32_t fp, uint32_t start)
134 {
135 SetFontName(fontName);
136 fp_ = fp;
137 start_ = start;
138 int32_t ret = lseek(fp_, start_, SEEK_SET);
139 if (ret < 0) {
140 GRAPHIC_LOGE("GlyphsFile::SetFile lseek failed");
141 return INVALID_RET_VALUE;
142 }
143 ret = read(fp_, &binHeader_, sizeof(binHeader_));
144 if (ret != sizeof(binHeader_)) {
145 GRAPHIC_LOGE("GlyphsFile::SetFile read failed");
146 return INVALID_RET_VALUE;
147 }
148 if (strncmp(binHeader_.fontMagic, FONT_MAGIC_NUMBER, FONT_MAGIC_NUM_LEN) != 0) {
149 return INVALID_RET_VALUE;
150 }
151 if (binHeader_.fontNum > UIFontBuilder::GetInstance()->GetBitmapFontIdMax()) {
152 GRAPHIC_LOGE("GlyphsFile::SetFile data error, fontNum need less than max fontId");
153 return INVALID_RET_VALUE;
154 }
155
156 fontNum_ = binHeader_.fontNum;
157 fontHeaderSectionStart_ = start_ + sizeof(binHeader_);
158 uint32_t size = sizeof(FontHeader) * fontNum_;
159 fontIndexSectionStart_ = fontHeaderSectionStart_ + size;
160
161 fontHeaderCache_ = reinterpret_cast<FontHeader*>(FontRamAllocator::GetInstance().Allocate(size));
162 if (fontHeaderCache_ == nullptr) {
163 GRAPHIC_LOGE("GlyphsFile::SetFile allocate font header cache failed");
164 return INVALID_RET_VALUE;
165 }
166
167 ret = read(fp_, fontHeaderCache_, size);
168 if (ret != static_cast<int32_t>(size)) {
169 GRAPHIC_LOGE("GlyphsFile::SetFile read failed");
170 return INVALID_RET_VALUE;
171 }
172
173 FontHeader* last = fontHeaderCache_ + fontNum_ - 1;
174 size = last->indexOffset + last->indexLen;
175 glyphNodeSectionStart_ = fontIndexSectionStart_ + size;
176
177 size = 0;
178 for (uint32_t i = 0; i < fontNum_; i++) {
179 size += fontHeaderCache_[i].glyphNum * sizeof(GlyphNode);
180 }
181 bitMapSectionStart_ = glyphNodeSectionStart_ + size;
182 ret = CacheInit();
183 if (ret == RET_VALUE_OK) {
184 isFileSet_ = true;
185 }
186
187 return ret;
188 }
189
IsSameFile(const char * fontName)190 bool GlyphsFile::IsSameFile(const char* fontName)
191 {
192 if ((fontName_ == nullptr) || (fontName == nullptr)) {
193 return false;
194 }
195
196 uint32_t Offset = 0;
197 uint32_t nameLen = strlen(fontName);
198 if (nameLen > FONT_NAME_LEN_MAX) {
199 Offset = nameLen - FONT_NAME_LEN_MAX;
200 }
201 return (strcmp(fontName_, fontName + Offset) == 0);
202 }
203
GetGlyphInfo(uint16_t fontId,GlyphInfo & glyphInfo)204 int8_t GlyphsFile::GetGlyphInfo(uint16_t fontId, GlyphInfo& glyphInfo)
205 {
206 uint16_t fontIdx = 0;
207 UIFontBuilder* fontBuilder = UIFontBuilder::GetInstance();
208 if (fontId > fontBuilder->GetBitmapFontIdMax()) {
209 GRAPHIC_LOGE("GlyphsFile::GetGlyphInfo fontId need less than max fontId");
210 return INVALID_RET_VALUE;
211 }
212 if (!isFileSet_) {
213 GRAPHIC_LOGE("GlyphsFile::GetGlyphInfo file not set");
214 return INVALID_RET_VALUE;
215 }
216
217 int32_t low = 0;
218 int32_t high = binHeader_.fontNum - 1;
219 bool found = false;
220
221 while (low <= high) {
222 int32_t mid = (low + high) / 2; // 2 means half
223 if (fontHeaderCache_[mid].fontId == fontId) {
224 fontIdx = mid;
225 found = true;
226 break;
227 } else if (fontHeaderCache_[mid].fontId > fontId) {
228 high = mid - 1;
229 } else if (fontHeaderCache_[mid].fontId < fontId) {
230 low = mid + 1;
231 }
232 }
233 if (!found) {
234 glyphInfo.fontHeader = nullptr;
235 glyphInfo.fontId = fontBuilder->GetBitmapFontIdMax();
236 return INVALID_RET_VALUE;
237 }
238
239 uint32_t size = 0;
240 glyphInfo.fontId = fontId;
241 glyphInfo.fontHeader = fontHeaderCache_ + fontIdx;
242 glyphInfo.fontIndexSectionStart = fontIndexSectionStart_ + glyphInfo.fontHeader->indexOffset;
243 for (uint32_t i = 0; i < fontIdx; i++) {
244 size += fontHeaderCache_[i].glyphNum * sizeof(GlyphNode);
245 }
246 glyphInfo.glyphNodeSectionStart = glyphNodeSectionStart_ + size;
247 glyphInfo.bitMapSectionStart = bitMapSectionStart_ + glyphInfo.fontHeader->glyphOffset;
248 glyphInfo.indexCache = indexCache_ + glyphInfo.fontHeader->indexOffset;
249
250 return RET_VALUE_OK;
251 }
252
GetFontVersion(const char * fontName,char * version,uint8_t len)253 int8_t GlyphsFile::GetFontVersion(const char* fontName, char* version, uint8_t len)
254 {
255 if (!isFileSet_ || (version == nullptr) || (len > FONT_VERSION_LEN)) {
256 GRAPHIC_LOGE("GlyphsFile::GetFontVersion invalid parameters");
257 return INVALID_RET_VALUE;
258 }
259
260 if (!IsSameFile(fontName)) {
261 return INVALID_RET_VALUE;
262 }
263
264 if (memset_s(version, len, 0, len) != EOK) {
265 GRAPHIC_LOGE("GlyphsFile::GetFontVersion memset_s failed");
266 return INVALID_RET_VALUE;
267 }
268 if (strcpy_s(version, len, binHeader_.fontVersion) != EOK) {
269 GRAPHIC_LOGE("GlyphsFile::GetFontVersion strcpy_s failed");
270 return INVALID_RET_VALUE;
271 }
272 return RET_VALUE_OK;
273 }
274
GetFontHeader(uint16_t fontId)275 const FontHeader* GlyphsFile::GetFontHeader(uint16_t fontId)
276 {
277 GlyphInfo glyphInfo;
278 int8_t ret = GetGlyphInfo(fontId, glyphInfo);
279 if (ret != RET_VALUE_OK) {
280 return nullptr;
281 }
282
283 return glyphInfo.fontHeader;
284 }
285
GetFontHeight(uint16_t fontId)286 int16_t GlyphsFile::GetFontHeight(uint16_t fontId)
287 {
288 GlyphInfo glyphInfo;
289 int8_t ret = GetGlyphInfo(fontId, glyphInfo);
290 if (ret != RET_VALUE_OK) {
291 return INVALID_RET_VALUE;
292 }
293
294 return glyphInfo.fontHeader->fontHeight;
295 }
296
GetBitmap(GlyphNode & node,BufferInfo & bufInfo)297 int8_t GlyphsFile::GetBitmap(GlyphNode& node, BufferInfo& bufInfo)
298 {
299 if (bufInfo.virAddr == nullptr) {
300 GRAPHIC_LOGE("GlyphsFile::GetBitmap invalid parameter");
301 return INVALID_RET_VALUE;
302 }
303
304 GlyphInfo glyphInfo;
305 int8_t result = GetGlyphInfo(node.fontId, glyphInfo);
306 if (result != RET_VALUE_OK) {
307 return INVALID_RET_VALUE;
308 }
309
310 uint32_t tmpBitMapSectionStart = glyphInfo.bitMapSectionStart;
311 uint32_t offset = tmpBitMapSectionStart + node.dataOff;
312 uint32_t size = node.kernOff - node.dataOff;
313 int32_t ret = lseek(fp_, offset, SEEK_SET);
314 if (ret != static_cast<int32_t>(offset)) {
315 GRAPHIC_LOGE("GlyphsFile::GetBitmap lseek failed");
316 return INVALID_RET_VALUE;
317 }
318
319 int32_t readSize = read(fp_, bufInfo.virAddr, size);
320 if (readSize != static_cast<int32_t>(size)) {
321 GRAPHIC_LOGE("GlyphsFile::GetBitmap read failed");
322 return INVALID_RET_VALUE;
323 }
324 UIFontAllocator::RearrangeBitmap(bufInfo, size, false);
325
326 node.dataFlag = node.fontId;
327 return RET_VALUE_OK;
328 }
329 } // namespace OHOS
330