/* * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "font/glyphs_file.h" #include "draw/draw_utils.h" #include "font/font_ram_allocator.h" #include "font/ui_font_builder.h" #include "gfx_utils/file.h" #include "gfx_utils/graphic_log.h" #include "securec.h" namespace OHOS { GlyphsFile::GlyphsFile() : binHeader_{{0}}, start_(0), fontHeaderSectionStart_(0), fontIndexSectionStart_(0), glyphNodeSectionStart_(0), bitMapSectionStart_(0), fontHeaderCache_(nullptr), indexCache_(nullptr), fontName_(nullptr), fp_(-1), isFileSet_(false), fontNum_(0) { } GlyphsFile::~GlyphsFile() { if (fontName_) { UIFree(fontName_); fontName_ = nullptr; } } int8_t GlyphsFile::CacheInit() { uint32_t size = 0; for (int32_t i = 0; i < fontNum_; i++) { size += fontHeaderCache_[i].indexLen; } indexCache_ = reinterpret_cast(FontRamAllocator::GetInstance().Allocate(size)); if (indexCache_ == nullptr) { GRAPHIC_LOGE("GlyphsFile::CacheInit Allocate failed"); return INVALID_RET_VALUE; } int32_t ret = read(fp_, indexCache_, size); if (ret != static_cast(size)) { GRAPHIC_LOGE("GlyphsFile::CacheInit read failed"); return INVALID_RET_VALUE; } return RET_VALUE_OK; } int8_t GlyphsFile::GetNodeFromFile(uint32_t unicode, uint16_t fontId, GlyphNode& node) { uint16_t idx = 0; uint32_t offset; GlyphInfo glyphInfo; int8_t result = GetGlyphInfo(fontId, glyphInfo); if (result != RET_VALUE_OK) { return INVALID_RET_VALUE; } for (int32_t i = RADIX_SHIFT_START; i >= 0; i -= RADIX_TREE_BITS) { offset = idx * sizeof(IndexNode); uint8_t key = static_cast((unicode >> static_cast(i)) & RADIX_TREE_MASK); offset += key * sizeof(uint16_t); idx = *(reinterpret_cast(glyphInfo.indexCache + offset)); if (idx == 0) { return INVALID_RET_VALUE; } } offset = glyphInfo.glyphNodeSectionStart + (idx - 1) * sizeof(GlyphNode); int32_t ret = lseek(fp_, offset, SEEK_SET); if (ret != static_cast(offset)) { GRAPHIC_LOGE("GlyphsFile::GetNodeFromFile lseek failed"); return INVALID_RET_VALUE; } ret = read(fp_, &node, sizeof(GlyphNode)); if (ret < 0) { GRAPHIC_LOGE("GlyphsFile::GetNodeFromFile read failed"); return INVALID_RET_VALUE; } return RET_VALUE_OK; } void GlyphsFile::SetFontName(const char* fontName) { if (fontName_ != nullptr) { return; } if (fontName == nullptr) { GRAPHIC_LOGE("GlyphsFile::SetFontName invalid parameters"); return; } uint32_t nameLen = strlen(fontName); if (nameLen > FONT_NAME_LEN_MAX) { nameLen = FONT_NAME_LEN_MAX; } else if (nameLen == 0) { return; } fontName_ = static_cast(UIMalloc(++nameLen)); if (fontName_ == nullptr) { return; } if (memcpy_s(fontName_, nameLen, fontName, nameLen) != EOK) { UIFree(fontName_); fontName_ = nullptr; } } int8_t GlyphsFile::SetFile(const char* fontName, int32_t fp, uint32_t start) { SetFontName(fontName); fp_ = fp; start_ = start; int32_t ret = lseek(fp_, start_, SEEK_SET); if (ret < 0) { GRAPHIC_LOGE("GlyphsFile::SetFile lseek failed"); return INVALID_RET_VALUE; } ret = read(fp_, &binHeader_, sizeof(binHeader_)); if (ret != sizeof(binHeader_)) { GRAPHIC_LOGE("GlyphsFile::SetFile read failed"); return INVALID_RET_VALUE; } if (strncmp(binHeader_.fontMagic, FONT_MAGIC_NUMBER, FONT_MAGIC_NUM_LEN) != 0) { return INVALID_RET_VALUE; } if (binHeader_.fontNum > UIFontBuilder::GetInstance()->GetBitmapFontIdMax()) { GRAPHIC_LOGE("GlyphsFile::SetFile data error, fontNum need less than max fontId"); return INVALID_RET_VALUE; } fontNum_ = binHeader_.fontNum; fontHeaderSectionStart_ = start_ + sizeof(binHeader_); uint32_t size = sizeof(FontHeader) * fontNum_; fontIndexSectionStart_ = fontHeaderSectionStart_ + size; fontHeaderCache_ = reinterpret_cast(FontRamAllocator::GetInstance().Allocate(size)); if (fontHeaderCache_ == nullptr) { GRAPHIC_LOGE("GlyphsFile::SetFile allocate font header cache failed"); return INVALID_RET_VALUE; } ret = read(fp_, fontHeaderCache_, size); if (ret != static_cast(size)) { GRAPHIC_LOGE("GlyphsFile::SetFile read failed"); return INVALID_RET_VALUE; } FontHeader* last = fontHeaderCache_ + fontNum_ - 1; size = last->indexOffset + last->indexLen; glyphNodeSectionStart_ = fontIndexSectionStart_ + size; size = 0; for (uint32_t i = 0; i < fontNum_; i++) { size += fontHeaderCache_[i].glyphNum * sizeof(GlyphNode); } bitMapSectionStart_ = glyphNodeSectionStart_ + size; ret = CacheInit(); if (ret == RET_VALUE_OK) { isFileSet_ = true; } return ret; } bool GlyphsFile::IsSameFile(const char* fontName) { if ((fontName_ == nullptr) || (fontName == nullptr)) { return false; } uint32_t Offset = 0; uint32_t nameLen = strlen(fontName); if (nameLen > FONT_NAME_LEN_MAX) { Offset = nameLen - FONT_NAME_LEN_MAX; } return (strcmp(fontName_, fontName + Offset) == 0); } int8_t GlyphsFile::GetGlyphInfo(uint16_t fontId, GlyphInfo& glyphInfo) { uint16_t fontIdx = 0; UIFontBuilder* fontBuilder = UIFontBuilder::GetInstance(); if (fontId > fontBuilder->GetBitmapFontIdMax()) { GRAPHIC_LOGE("GlyphsFile::GetGlyphInfo fontId need less than max fontId"); return INVALID_RET_VALUE; } if (!isFileSet_) { GRAPHIC_LOGE("GlyphsFile::GetGlyphInfo file not set"); return INVALID_RET_VALUE; } int32_t low = 0; int32_t high = binHeader_.fontNum - 1; bool found = false; while (low <= high) { int32_t mid = (low + high) / 2; // 2 means half if (fontHeaderCache_[mid].fontId == fontId) { fontIdx = mid; found = true; break; } else if (fontHeaderCache_[mid].fontId > fontId) { high = mid - 1; } else if (fontHeaderCache_[mid].fontId < fontId) { low = mid + 1; } } if (!found) { glyphInfo.fontHeader = nullptr; glyphInfo.fontId = fontBuilder->GetBitmapFontIdMax(); return INVALID_RET_VALUE; } uint32_t size = 0; glyphInfo.fontId = fontId; glyphInfo.fontHeader = fontHeaderCache_ + fontIdx; glyphInfo.fontIndexSectionStart = fontIndexSectionStart_ + glyphInfo.fontHeader->indexOffset; for (uint32_t i = 0; i < fontIdx; i++) { size += fontHeaderCache_[i].glyphNum * sizeof(GlyphNode); } glyphInfo.glyphNodeSectionStart = glyphNodeSectionStart_ + size; glyphInfo.bitMapSectionStart = bitMapSectionStart_ + glyphInfo.fontHeader->glyphOffset; glyphInfo.indexCache = indexCache_ + glyphInfo.fontHeader->indexOffset; return RET_VALUE_OK; } int8_t GlyphsFile::GetFontVersion(const char* fontName, char* version, uint8_t len) { if (!isFileSet_ || (version == nullptr) || (len > FONT_VERSION_LEN)) { GRAPHIC_LOGE("GlyphsFile::GetFontVersion invalid parameters"); return INVALID_RET_VALUE; } if (!IsSameFile(fontName)) { return INVALID_RET_VALUE; } if (memset_s(version, len, 0, len) != EOK) { GRAPHIC_LOGE("GlyphsFile::GetFontVersion memset_s failed"); return INVALID_RET_VALUE; } if (strcpy_s(version, len, binHeader_.fontVersion) != EOK) { GRAPHIC_LOGE("GlyphsFile::GetFontVersion strcpy_s failed"); return INVALID_RET_VALUE; } return RET_VALUE_OK; } const FontHeader* GlyphsFile::GetFontHeader(uint16_t fontId) { GlyphInfo glyphInfo; int8_t ret = GetGlyphInfo(fontId, glyphInfo); if (ret != RET_VALUE_OK) { return nullptr; } return glyphInfo.fontHeader; } int16_t GlyphsFile::GetFontHeight(uint16_t fontId) { GlyphInfo glyphInfo; int8_t ret = GetGlyphInfo(fontId, glyphInfo); if (ret != RET_VALUE_OK) { return INVALID_RET_VALUE; } return glyphInfo.fontHeader->fontHeight; } int8_t GlyphsFile::GetBitmap(GlyphNode& node, BufferInfo& bufInfo) { if (bufInfo.virAddr == nullptr) { GRAPHIC_LOGE("GlyphsFile::GetBitmap invalid parameter"); return INVALID_RET_VALUE; } GlyphInfo glyphInfo; int8_t result = GetGlyphInfo(node.fontId, glyphInfo); if (result != RET_VALUE_OK) { return INVALID_RET_VALUE; } uint32_t tmpBitMapSectionStart = glyphInfo.bitMapSectionStart; uint32_t offset = tmpBitMapSectionStart + node.dataOff; uint32_t size = node.kernOff - node.dataOff; int32_t ret = lseek(fp_, offset, SEEK_SET); if (ret != static_cast(offset)) { GRAPHIC_LOGE("GlyphsFile::GetBitmap lseek failed"); return INVALID_RET_VALUE; } int32_t readSize = read(fp_, bufInfo.virAddr, size); if (readSize != static_cast(size)) { GRAPHIC_LOGE("GlyphsFile::GetBitmap read failed"); return INVALID_RET_VALUE; } UIFontAllocator::RearrangeBitmap(bufInfo, size, false); node.dataFlag = node.fontId; return RET_VALUE_OK; } } // namespace OHOS