* 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) {
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;
chunk = reinterpret_cast<struct Chunk*>(ram_);
chunk->next = size - sizeof(struct Chunk);
chunk->prev = 0;
chunk->used = false;
end_ = reinterpret_cast<struct Chunk*>(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<struct Chunk*>(static_cast<uint8_t*>(addr) - sizeof(struct Chunk));
return chunk->next - (reinterpret_cast<uint8_t*>(addr) - reinterpret_cast<uint8_t*>(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<uint8_t*>(free_) - ram_; ptr < ramSize_;
ptr = reinterpret_cast<struct Chunk*>(ram_ + ptr)->next) {
chunk = reinterpret_cast<struct Chunk*>(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<struct Chunk*>(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<struct Chunk*>(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<struct Chunk*>(ram_ + cur->next);
}
free_ = cur;
}
return reinterpret_cast<uint8_t*>(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<struct Chunk*>(ram_ + chunk->next);
if (((nextChunk != chunk) && !(nextChunk->used)) && (nextChunk != end_)) {
if (free_ == nextChunk) {
free_ = chunk;
}
chunk->next = nextChunk->next;
reinterpret_cast<struct Chunk*>(ram_ + nextChunk->next)->prev = reinterpret_cast<uint8_t*>(chunk) - ram_;
}
prevChunk = reinterpret_cast<struct Chunk*>(ram_ + chunk->prev);
if ((prevChunk != chunk) && !(prevChunk->used)) {
if (free_ == chunk) {
free_ = prevChunk;
}
prevChunk->next = chunk->next;
reinterpret_cast<struct Chunk*>(ram_ + chunk->next)->prev = reinterpret_cast<uint8_t*>(prevChunk) - ram_;
}
}
void UIFontAllocator::Free(void* addr)
{
struct Chunk* chunk = nullptr;
if (addr == nullptr) {
return;
}
if ((reinterpret_cast<uint8_t*>(addr) < ram_) ||
(reinterpret_cast<uint8_t*>(addr) > reinterpret_cast<uint8_t*>(end_))) {
return;
}
chunk = reinterpret_cast<struct Chunk*>(static_cast<uint8_t*>(addr) - sizeof(struct Chunk));
chunk->used = false;
if (chunk < free_) {
free_ = chunk;
}
freeSize_ += chunk->next - (reinterpret_cast<uint8_t*>(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<void*>(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<uint8_t*>(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;
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();
}
}