/* * Copyright (c) 2020-2021 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/ui_font_allocator.h" #include "draw/draw_utils.h" #include "engines/gfx/gfx_engine_manager.h" #include "font/ui_font.h" #include "font/ui_font_cache_manager.h" #include "gfx_utils/graphic_buffer.h" namespace OHOS { UIFontAllocator::UIFontAllocator() : ram_(nullptr), ramSize_(0), freeSize_(0), minSize_(0), end_(nullptr), free_(nullptr) { } UIFontAllocator::~UIFontAllocator() {} void UIFontAllocator::SetRamAddr(uint8_t* ram, uint32_t size) { if (size <= sizeof(struct Chunk) * 2) { // 2 : head and tail two chunk ramSize_ = 0; return; } if (ram == nullptr) { ramSize_ = 0; return; } UI_ADDR_ALIGN(ram, size); ram_ = ram; struct Chunk* chunk = nullptr; ramSize_ = size - sizeof(struct Chunk) * 2; // head and tail two chunk chunk = reinterpret_cast(ram_); chunk->next = size - sizeof(struct Chunk); chunk->prev = 0; chunk->used = false; end_ = reinterpret_cast(ram_ + size - sizeof(struct Chunk)); end_->next = size - sizeof(struct Chunk); end_->prev = size - sizeof(struct Chunk); end_->used = true; free_ = chunk; freeSize_ = size - sizeof(struct Chunk); } uint32_t UIFontAllocator::GetSize(void* addr) { struct Chunk* chunk = reinterpret_cast(static_cast(addr) - sizeof(struct Chunk)); return chunk->next - (reinterpret_cast(addr) - reinterpret_cast(ram_)); } void UIFontAllocator::SetMinChunkSize(uint32_t size) { minSize_ = UI_ALIGN_UP(size); } void* UIFontAllocator::Allocate(uint32_t size) { uint32_t free; uint32_t left; struct Chunk* chunk = nullptr; struct Chunk* chunk2 = nullptr; struct Chunk* chunk3 = nullptr; size = UI_ALIGN_UP(size); if (size < minSize_) { size = minSize_; } for (uint32_t ptr = reinterpret_cast(free_) - ram_; ptr < ramSize_; ptr = reinterpret_cast(ram_ + ptr)->next) { chunk = reinterpret_cast(ram_ + ptr); if (chunk->used) { continue; } free = chunk->next - ptr; if (free < sizeof(struct Chunk) + size) { continue; } left = free - sizeof(struct Chunk) - size; if (left >= sizeof(struct Chunk) + minSize_) { uint32_t ptr2 = ptr + sizeof(struct Chunk) + size; chunk2 = reinterpret_cast(ram_ + ptr2); chunk2->used = false; chunk2->next = chunk->next; chunk2->prev = ptr; chunk->next = ptr2; chunk->used = true; if (chunk2->next != end_->next) { chunk3 = reinterpret_cast(ram_ + chunk2->next); chunk3->prev = ptr2; } freeSize_ -= size + sizeof(struct Chunk); } else { chunk->used = true; freeSize_ -= chunk->next - ptr; } if (chunk == free_) { struct Chunk* cur = free_; while (cur->used && (cur != end_)) { cur = reinterpret_cast(ram_ + cur->next); } free_ = cur; } return reinterpret_cast(chunk) + sizeof(struct Chunk); } return nullptr; } void UIFontAllocator::CombineFree(struct Chunk* chunk) { if (chunk == nullptr) { return; } struct Chunk* nextChunk = nullptr; struct Chunk* prevChunk = nullptr; nextChunk = reinterpret_cast(ram_ + chunk->next); if (((nextChunk != chunk) && !(nextChunk->used)) && (nextChunk != end_)) { if (free_ == nextChunk) { free_ = chunk; } chunk->next = nextChunk->next; reinterpret_cast(ram_ + nextChunk->next)->prev = reinterpret_cast(chunk) - ram_; } prevChunk = reinterpret_cast(ram_ + chunk->prev); if ((prevChunk != chunk) && !(prevChunk->used)) { if (free_ == chunk) { free_ = prevChunk; } prevChunk->next = chunk->next; reinterpret_cast(ram_ + chunk->next)->prev = reinterpret_cast(prevChunk) - ram_; } } void UIFontAllocator::Free(void* addr) { struct Chunk* chunk = nullptr; if (addr == nullptr) { return; } if ((reinterpret_cast(addr) < ram_) || (reinterpret_cast(addr) > reinterpret_cast(end_))) { return; } chunk = reinterpret_cast(static_cast(addr) - sizeof(struct Chunk)); chunk->used = false; if (chunk < free_) { free_ = chunk; } freeSize_ += chunk->next - (reinterpret_cast(chunk) - ram_); CombineFree(chunk); } BufferInfo UIFontAllocator::GetCacheBuffer(uint16_t fontId, uint32_t unicode, ColorMode mode, GlyphNode& glyphNode, bool hasMetric, TextStyle textStyle) { BufferInfo bufInfo{Rect(), 0, nullptr, nullptr, glyphNode.cols, glyphNode.rows, mode, 0}; bufInfo.stride = BIT_TO_BYTE(bufInfo.width * DrawUtils::GetPxSizeByColorMode(bufInfo.mode)); BaseGfxEngine::GetInstance()->AdjustLineStride(bufInfo); uint32_t bitmapSize = bufInfo.stride * bufInfo.height; if (hasMetric) { bitmapSize += sizeof(Metric); } bufInfo.virAddr = reinterpret_cast(UIFontCacheManager::GetInstance()->GetSpace(fontId, unicode, bitmapSize, textStyle)); return bufInfo; } void UIFontAllocator::RearrangeBitmap(BufferInfo& bufInfo, uint32_t fileSz, bool hasMetric) { uint32_t word = bufInfo.width; word = BIT_TO_BYTE(word * DrawUtils::GetPxSizeByColorMode(bufInfo.mode)); if (bufInfo.stride <= word) { return; } uint8_t* bitmap = reinterpret_cast(bufInfo.virAddr); if (hasMetric) { bitmap += sizeof(Metric); } uint32_t suffixLen = bufInfo.stride - word; uint8_t* rdestBuf = bitmap + bufInfo.stride * bufInfo.height; uint8_t* rsrcBuf = bitmap + fileSz; /* Rearrange bitmap in local buffer */ for (uint32_t row = 0; row < bufInfo.height; row++) { rdestBuf -= suffixLen; (void)memset_s(rdestBuf, suffixLen, 0, suffixLen); for (uint32_t i = 0; i < word; i++) { *(--rdestBuf) = *(--rsrcBuf); } } BaseGfxEngine::GetInstance()->MemoryBarrier(); } } // namespace OHOS