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 24namespace OHOS { 25GlyphsFile::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} 40GlyphsFile::~GlyphsFile() 41{ 42 if (fontName_) { 43 UIFree(fontName_); 44 fontName_ = nullptr; 45 } 46} 47 48int8_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 70int8_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 105void 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 133int8_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 190bool 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 204int8_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 253int8_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 275const 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 286int16_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 297int8_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