18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci
168bf80f4bSopenharmony_ci
178bf80f4bSopenharmony_ci#include "font_manager.h"
188bf80f4bSopenharmony_ci
198bf80f4bSopenharmony_ci#include <algorithm>
208bf80f4bSopenharmony_ci#include <freetype/ftsizes.h>
218bf80f4bSopenharmony_ci#include <freetype/tttables.h>
228bf80f4bSopenharmony_ci#include <numeric>
238bf80f4bSopenharmony_ci
248bf80f4bSopenharmony_ci#include <base/containers/fixed_string.h>
258bf80f4bSopenharmony_ci#include <base/containers/string.h>
268bf80f4bSopenharmony_ci#include <core/intf_engine.h>
278bf80f4bSopenharmony_ci#include <core/io/intf_file_manager.h>
288bf80f4bSopenharmony_ci#include <core/log.h>
298bf80f4bSopenharmony_ci#include <render/datastore/intf_render_data_store_default_staging.h>
308bf80f4bSopenharmony_ci#include <render/datastore/intf_render_data_store_manager.h>
318bf80f4bSopenharmony_ci#include <render/device/gpu_resource_desc.h>
328bf80f4bSopenharmony_ci#include <render/device/intf_gpu_resource_manager.h>
338bf80f4bSopenharmony_ci#include <render/intf_render_context.h>
348bf80f4bSopenharmony_ci
358bf80f4bSopenharmony_ci#include "face_data.h"
368bf80f4bSopenharmony_ci#include "font.h"
378bf80f4bSopenharmony_ci#include "font_buffer.h"
388bf80f4bSopenharmony_ci
398bf80f4bSopenharmony_ciusing namespace BASE_NS;
408bf80f4bSopenharmony_ciusing namespace BASE_NS::Math;
418bf80f4bSopenharmony_ciusing namespace CORE_NS;
428bf80f4bSopenharmony_ciusing namespace RENDER_NS;
438bf80f4bSopenharmony_ciusing namespace FONT_NS::FontDefs;
448bf80f4bSopenharmony_ci
458bf80f4bSopenharmony_ciFONT_BEGIN_NAMESPACE()
468bf80f4bSopenharmony_ci
478bf80f4bSopenharmony_cinamespace {
488bf80f4bSopenharmony_cistring GetErrorString()
498bf80f4bSopenharmony_ci{
508bf80f4bSopenharmony_ci    // Visual Studio lacks strerrorlen_s so need to define a fixed "large enough" buffer
518bf80f4bSopenharmony_ci    char buffer[64u];
528bf80f4bSopenharmony_ci#ifdef _WIN32
538bf80f4bSopenharmony_ci    strerror_s(buffer, sizeof(buffer), errno);
548bf80f4bSopenharmony_ci#else
558bf80f4bSopenharmony_ci    strerror_r(errno, buffer, sizeof(buffer));
568bf80f4bSopenharmony_ci#endif
578bf80f4bSopenharmony_ci    return string(buffer);
588bf80f4bSopenharmony_ci}
598bf80f4bSopenharmony_ci
608bf80f4bSopenharmony_ciconstexpr string_view RENDER_DATA_STORE_DEFAULT_STAGING = "RenderDataStoreDefaultStaging";
618bf80f4bSopenharmony_ci
628bf80f4bSopenharmony_ciconst Width widths_os2_match[] = { Width::UltraCondensed, Width::ExtraCondensed, Width::Condensed, Width::SemiCondensed,
638bf80f4bSopenharmony_ci    Width::Normal, Width::SemiExpanded, Width::Expanded, Width::ExtraExpanded, Width::UltraExpanded };
648bf80f4bSopenharmony_ci
658bf80f4bSopenharmony_ciTypeFace InitTypeFace(FT_Face face, string_view path, string_view filename)
668bf80f4bSopenharmony_ci{
678bf80f4bSopenharmony_ci    TypeFace typeFace {
688bf80f4bSopenharmony_ci        string(path),            // font file path
698bf80f4bSopenharmony_ci        face->family_name,       // family name as defined in font file
708bf80f4bSopenharmony_ci        face->style_name,        // style name as defined in font file
718bf80f4bSopenharmony_ci        BASE_NS::hash(filename), // physical PATH hash as map key for font buffers map
728bf80f4bSopenharmony_ci        face->face_index,        // face index for quick access to face in font file
738bf80f4bSopenharmony_ci        Regular,                 // style
748bf80f4bSopenharmony_ci    };
758bf80f4bSopenharmony_ci    TT_OS2* tblOS2 = (TT_OS2*)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
768bf80f4bSopenharmony_ci    if (tblOS2) {
778bf80f4bSopenharmony_ci        typeFace.style.Weight = static_cast<Weight>(tblOS2->usWeightClass);
788bf80f4bSopenharmony_ci        typeFace.style.Width = widths_os2_match[tblOS2->usWidthClass];
798bf80f4bSopenharmony_ci    } else {
808bf80f4bSopenharmony_ci        if (face->style_flags & 0x02) {
818bf80f4bSopenharmony_ci            typeFace.style.Weight = Weight::Bold;
828bf80f4bSopenharmony_ci        }
838bf80f4bSopenharmony_ci    }
848bf80f4bSopenharmony_ci    if (face->style_flags & 0x01) {
858bf80f4bSopenharmony_ci        typeFace.style.SlantType = SlantType::Italic;
868bf80f4bSopenharmony_ci    }
878bf80f4bSopenharmony_ci    return typeFace;
888bf80f4bSopenharmony_ci}
898bf80f4bSopenharmony_ci} // namespace
908bf80f4bSopenharmony_ci
918bf80f4bSopenharmony_ciFontManager::FontManager(IRenderContext& context) : renderContext_(context)
928bf80f4bSopenharmony_ci{
938bf80f4bSopenharmony_ci    if (FT_Init_FreeType(&fontLib_)) {
948bf80f4bSopenharmony_ci        CORE_LOG_E("failed to init freetype library: %s", GetErrorString().c_str());
958bf80f4bSopenharmony_ci    }
968bf80f4bSopenharmony_ci
978bf80f4bSopenharmony_ci    GetTypeFacesByDir(typeFaces_, "fonts://");
988bf80f4bSopenharmony_ci}
998bf80f4bSopenharmony_ci
1008bf80f4bSopenharmony_ciFontManager::~FontManager()
1018bf80f4bSopenharmony_ci{
1028bf80f4bSopenharmony_ci    FT_Done_FreeType(fontLib_);
1038bf80f4bSopenharmony_ci    fontLib_ = nullptr;
1048bf80f4bSopenharmony_ci}
1058bf80f4bSopenharmony_ci
1068bf80f4bSopenharmony_ciarray_view<const TypeFace> FontManager::GetTypeFaces() const
1078bf80f4bSopenharmony_ci{
1088bf80f4bSopenharmony_ci    return typeFaces_;
1098bf80f4bSopenharmony_ci}
1108bf80f4bSopenharmony_ci
1118bf80f4bSopenharmony_ciconst TypeFace* FontManager::GetTypeFace(string_view name, string_view styleName)
1128bf80f4bSopenharmony_ci{
1138bf80f4bSopenharmony_ci    for (auto& typeFace : typeFaces_) {
1148bf80f4bSopenharmony_ci        if (typeFace.name == name) {
1158bf80f4bSopenharmony_ci            if (styleName.empty() || typeFace.styleName == styleName) {
1168bf80f4bSopenharmony_ci                return &typeFace;
1178bf80f4bSopenharmony_ci            }
1188bf80f4bSopenharmony_ci        }
1198bf80f4bSopenharmony_ci    }
1208bf80f4bSopenharmony_ci    return nullptr;
1218bf80f4bSopenharmony_ci}
1228bf80f4bSopenharmony_ci
1238bf80f4bSopenharmony_civector<TypeFace> FontManager::GetTypeFaces(const string_view filePath)
1248bf80f4bSopenharmony_ci{
1258bf80f4bSopenharmony_ci    vector<TypeFace> typeFaces;
1268bf80f4bSopenharmony_ci    GetTypeFacesByFile(typeFaces, filePath);
1278bf80f4bSopenharmony_ci    return typeFaces;
1288bf80f4bSopenharmony_ci}
1298bf80f4bSopenharmony_ci
1308bf80f4bSopenharmony_civector<TypeFace> FontManager::GetTypeFaces(array_view<const string_view> lookupDirs)
1318bf80f4bSopenharmony_ci{
1328bf80f4bSopenharmony_ci    vector<TypeFace> typeFaces;
1338bf80f4bSopenharmony_ci    for (const auto& dir : lookupDirs) {
1348bf80f4bSopenharmony_ci        GetTypeFacesByDir(typeFaces, dir);
1358bf80f4bSopenharmony_ci    }
1368bf80f4bSopenharmony_ci    return typeFaces;
1378bf80f4bSopenharmony_ci}
1388bf80f4bSopenharmony_ci
1398bf80f4bSopenharmony_cistd::shared_ptr<FontBuffer> FontManager::CreateFontBuffer(const TypeFace& typeFace)
1408bf80f4bSopenharmony_ci{
1418bf80f4bSopenharmony_ci    {
1428bf80f4bSopenharmony_ci        std::shared_lock readerLock(fontBuffersMutex_);
1438bf80f4bSopenharmony_ci
1448bf80f4bSopenharmony_ci        if (auto it = fontBuffers_.find(typeFace.uid); it != fontBuffers_.end()) {
1458bf80f4bSopenharmony_ci            if (auto fromWeak = it->second.lock()) {
1468bf80f4bSopenharmony_ci                return fromWeak;
1478bf80f4bSopenharmony_ci            }
1488bf80f4bSopenharmony_ci        }
1498bf80f4bSopenharmony_ci    }
1508bf80f4bSopenharmony_ci
1518bf80f4bSopenharmony_ci    std::lock_guard writerLock(fontBuffersMutex_);
1528bf80f4bSopenharmony_ci
1538bf80f4bSopenharmony_ci    if (auto it = fontBuffers_.find(typeFace.uid); it != fontBuffers_.end()) {
1548bf80f4bSopenharmony_ci        if (auto fromWeak = it->second.lock()) {
1558bf80f4bSopenharmony_ci            return fromWeak;
1568bf80f4bSopenharmony_ci        }
1578bf80f4bSopenharmony_ci    }
1588bf80f4bSopenharmony_ci
1598bf80f4bSopenharmony_ci    auto& fileManager = renderContext_.GetEngine().GetFileManager();
1608bf80f4bSopenharmony_ci    IFile::Ptr file = fileManager.OpenFile(typeFace.path);
1618bf80f4bSopenharmony_ci    if (file == nullptr) {
1628bf80f4bSopenharmony_ci        CORE_LOG_E("failed to open font %s | %s", typeFace.path.data(), GetErrorString().c_str());
1638bf80f4bSopenharmony_ci        return nullptr;
1648bf80f4bSopenharmony_ci    }
1658bf80f4bSopenharmony_ci
1668bf80f4bSopenharmony_ci    const size_t len = static_cast<size_t>(file->GetLength());
1678bf80f4bSopenharmony_ci    vector<uint8_t> bytes;
1688bf80f4bSopenharmony_ci    bytes.resize(len);
1698bf80f4bSopenharmony_ci
1708bf80f4bSopenharmony_ci    if (len != file->Read(bytes.data(), bytes.size())) {
1718bf80f4bSopenharmony_ci        CORE_LOG_E("failed to read %zu bytes from %s | %s", len, typeFace.path.data(), GetErrorString().c_str());
1728bf80f4bSopenharmony_ci        return nullptr;
1738bf80f4bSopenharmony_ci    }
1748bf80f4bSopenharmony_ci
1758bf80f4bSopenharmony_ci    auto fb = std::make_shared<FontBuffer>(this, typeFace.uid, bytes);
1768bf80f4bSopenharmony_ci
1778bf80f4bSopenharmony_ci    fontBuffers_.insert({ typeFace.uid, fb });
1788bf80f4bSopenharmony_ci    CORE_LOG_N("create FontBuffer %p", this);
1798bf80f4bSopenharmony_ci
1808bf80f4bSopenharmony_ci    return fb;
1818bf80f4bSopenharmony_ci}
1828bf80f4bSopenharmony_ci
1838bf80f4bSopenharmony_ciIFont::Ptr FontManager::CreateFont(const TypeFace& typeFace)
1848bf80f4bSopenharmony_ci{
1858bf80f4bSopenharmony_ci    std::shared_ptr fontBuff = CreateFontBuffer(typeFace);
1868bf80f4bSopenharmony_ci    if (!fontBuff) {
1878bf80f4bSopenharmony_ci        return nullptr;
1888bf80f4bSopenharmony_ci    }
1898bf80f4bSopenharmony_ci    std::shared_ptr<FaceData> face = fontBuff->CreateFace(typeFace.index);
1908bf80f4bSopenharmony_ci    if (!face) {
1918bf80f4bSopenharmony_ci        return nullptr;
1928bf80f4bSopenharmony_ci    }
1938bf80f4bSopenharmony_ci    Font::Ptr font = Font::Ptr(new Font(std::move(face)));
1948bf80f4bSopenharmony_ci
1958bf80f4bSopenharmony_ci    return font;
1968bf80f4bSopenharmony_ci}
1978bf80f4bSopenharmony_ci
1988bf80f4bSopenharmony_ciIFont::Ptr FontManager::CreateFontFromMemory(const TypeFace& typeFace, const BASE_NS::vector<uint8_t>& buffer)
1998bf80f4bSopenharmony_ci{
2008bf80f4bSopenharmony_ci    std::shared_ptr<FontBuffer> fontBuff;
2018bf80f4bSopenharmony_ci    {
2028bf80f4bSopenharmony_ci        std::shared_lock readerLock(fontBuffersMutex_);
2038bf80f4bSopenharmony_ci        if (auto it = fontBuffers_.find(typeFace.uid); it != fontBuffers_.end()) {
2048bf80f4bSopenharmony_ci            fontBuff = it->second.lock();
2058bf80f4bSopenharmony_ci        }
2068bf80f4bSopenharmony_ci    }
2078bf80f4bSopenharmony_ci    if (!fontBuff) {
2088bf80f4bSopenharmony_ci        std::lock_guard writerLock(fontBuffersMutex_);
2098bf80f4bSopenharmony_ci        if (auto it = fontBuffers_.find(typeFace.uid); it != fontBuffers_.end()) {
2108bf80f4bSopenharmony_ci            fontBuff = it->second.lock();
2118bf80f4bSopenharmony_ci        }
2128bf80f4bSopenharmony_ci        if (!fontBuff) {
2138bf80f4bSopenharmony_ci            fontBuff = std::make_shared<FontBuffer>(this, typeFace.uid, buffer);
2148bf80f4bSopenharmony_ci            fontBuffers_.insert({ typeFace.uid, fontBuff });
2158bf80f4bSopenharmony_ci        }
2168bf80f4bSopenharmony_ci    }
2178bf80f4bSopenharmony_ci    if (!fontBuff) {
2188bf80f4bSopenharmony_ci        return {};
2198bf80f4bSopenharmony_ci    }
2208bf80f4bSopenharmony_ci
2218bf80f4bSopenharmony_ci    return Font::Ptr(new Font(fontBuff->CreateFace(typeFace.index)));
2228bf80f4bSopenharmony_ci}
2238bf80f4bSopenharmony_ci
2248bf80f4bSopenharmony_ciuint32_t FontManager::GetGlyphIndex(const TypeFace& typeFace, uint32_t code)
2258bf80f4bSopenharmony_ci{
2268bf80f4bSopenharmony_ci    auto fontBuff = CreateFontBuffer(typeFace);
2278bf80f4bSopenharmony_ci    if (!fontBuff) {
2288bf80f4bSopenharmony_ci        return 0;
2298bf80f4bSopenharmony_ci    }
2308bf80f4bSopenharmony_ci    auto face = fontBuff->CreateFace(typeFace.index);
2318bf80f4bSopenharmony_ci    if (!face) {
2328bf80f4bSopenharmony_ci        return 0;
2338bf80f4bSopenharmony_ci    }
2348bf80f4bSopenharmony_ci    return face->GetGlyphIndex(code);
2358bf80f4bSopenharmony_ci}
2368bf80f4bSopenharmony_ci
2378bf80f4bSopenharmony_civoid FontManager::FlushCaches()
2388bf80f4bSopenharmony_ci{
2398bf80f4bSopenharmony_ci    UploadPending();
2408bf80f4bSopenharmony_ci    std::lock_guard writerLock(atlasMutex_);
2418bf80f4bSopenharmony_ci    atlasTextures_.clear();
2428bf80f4bSopenharmony_ci    CORE_LOG_N("atlas textures flush");
2438bf80f4bSopenharmony_ci}
2448bf80f4bSopenharmony_ci
2458bf80f4bSopenharmony_civoid FontManager::GetTypeFacesByFile(vector<TypeFace>& typeFaces, string_view path)
2468bf80f4bSopenharmony_ci{
2478bf80f4bSopenharmony_ci    auto& fileManager = renderContext_.GetEngine().GetFileManager();
2488bf80f4bSopenharmony_ci
2498bf80f4bSopenharmony_ci    IFile::Ptr file = fileManager.OpenFile(path);
2508bf80f4bSopenharmony_ci    if (file == nullptr) {
2518bf80f4bSopenharmony_ci        CORE_LOG_E("failed to open font %s | %s", path.data(), GetErrorString().c_str());
2528bf80f4bSopenharmony_ci        return;
2538bf80f4bSopenharmony_ci    }
2548bf80f4bSopenharmony_ci
2558bf80f4bSopenharmony_ci    auto entry = fileManager.GetEntry(path);
2568bf80f4bSopenharmony_ci    const size_t len = static_cast<size_t>(file->GetLength());
2578bf80f4bSopenharmony_ci    vector<uint8_t> buf(len);
2588bf80f4bSopenharmony_ci
2598bf80f4bSopenharmony_ci    if (len != file->Read(buf.data(), buf.size())) {
2608bf80f4bSopenharmony_ci        CORE_LOG_E("failed to read %zu bytes from %s | %s", len, path.data(), GetErrorString().c_str());
2618bf80f4bSopenharmony_ci        return;
2628bf80f4bSopenharmony_ci    }
2638bf80f4bSopenharmony_ci
2648bf80f4bSopenharmony_ci    if (buf.empty()) {
2658bf80f4bSopenharmony_ci        return;
2668bf80f4bSopenharmony_ci    }
2678bf80f4bSopenharmony_ci
2688bf80f4bSopenharmony_ci    FT_Long numFaces = 0;
2698bf80f4bSopenharmony_ci    FT_Long numInstances = 0;
2708bf80f4bSopenharmony_ci    FT_Long faceIndex = 0;
2718bf80f4bSopenharmony_ci    FT_Long instanceIndex = 0;
2728bf80f4bSopenharmony_ci
2738bf80f4bSopenharmony_ci    constexpr uint8_t INSTANCE_SHIFT = 16u;
2748bf80f4bSopenharmony_ci
2758bf80f4bSopenharmony_ci    do {
2768bf80f4bSopenharmony_ci        FT_Long faceId = (instanceIndex << INSTANCE_SHIFT) + faceIndex;
2778bf80f4bSopenharmony_ci        auto face = OpenFtFace(buf, faceId);
2788bf80f4bSopenharmony_ci        // lume api is utf8, unicode is the default charmap with freetype.
2798bf80f4bSopenharmony_ci        if (face && face->charmap) {
2808bf80f4bSopenharmony_ci            typeFaces.push_back(InitTypeFace(face, path, entry.name));
2818bf80f4bSopenharmony_ci
2828bf80f4bSopenharmony_ci            numFaces = face->num_faces;
2838bf80f4bSopenharmony_ci            numInstances = face->style_flags >> INSTANCE_SHIFT;
2848bf80f4bSopenharmony_ci
2858bf80f4bSopenharmony_ci            CORE_LOG_N("%s", path.data());
2868bf80f4bSopenharmony_ci            CORE_LOG_N("  number of faces:     %ld", numFaces);
2878bf80f4bSopenharmony_ci            CORE_LOG_N("  number of instances: %ld", numInstances);
2888bf80f4bSopenharmony_ci
2898bf80f4bSopenharmony_ci            if (instanceIndex < numInstances) {
2908bf80f4bSopenharmony_ci                ++instanceIndex;
2918bf80f4bSopenharmony_ci            } else {
2928bf80f4bSopenharmony_ci                ++faceIndex;
2938bf80f4bSopenharmony_ci                instanceIndex = 0;
2948bf80f4bSopenharmony_ci            }
2958bf80f4bSopenharmony_ci            FT_Done_Face(face);
2968bf80f4bSopenharmony_ci        } else {
2978bf80f4bSopenharmony_ci            CORE_LOG_W("failed to create face: %s", path.data());
2988bf80f4bSopenharmony_ci        }
2998bf80f4bSopenharmony_ci    } while (faceIndex < numFaces);
3008bf80f4bSopenharmony_ci}
3018bf80f4bSopenharmony_ci
3028bf80f4bSopenharmony_civoid FontManager::GetTypeFacesByDir(vector<TypeFace>& typeFaces, string_view path)
3038bf80f4bSopenharmony_ci{
3048bf80f4bSopenharmony_ci    auto& fileManager = renderContext_.GetEngine().GetFileManager();
3058bf80f4bSopenharmony_ci    IDirectory::Ptr dir = fileManager.OpenDirectory(path);
3068bf80f4bSopenharmony_ci    if (!dir) {
3078bf80f4bSopenharmony_ci        return;
3088bf80f4bSopenharmony_ci    }
3098bf80f4bSopenharmony_ci
3108bf80f4bSopenharmony_ci    vector<IDirectory::Entry> const files = dir->GetEntries();
3118bf80f4bSopenharmony_ci    CORE_LOG_N("check dir '%s' with %zu entries", path.data(), files.size());
3128bf80f4bSopenharmony_ci
3138bf80f4bSopenharmony_ci    for (auto const& file : files) {
3148bf80f4bSopenharmony_ci        if (file.type == IDirectory::Entry::Type::FILE) {
3158bf80f4bSopenharmony_ci            GetTypeFacesByFile(typeFaces, path + file.name);
3168bf80f4bSopenharmony_ci        }
3178bf80f4bSopenharmony_ci    }
3188bf80f4bSopenharmony_ci}
3198bf80f4bSopenharmony_ci
3208bf80f4bSopenharmony_ciFT_Face FontManager::OpenFtFace(array_view<const uint8_t> buf, FT_Long index)
3218bf80f4bSopenharmony_ci{
3228bf80f4bSopenharmony_ci    CORE_ASSERT_MSG(fontLib_, "font library is not initialized");
3238bf80f4bSopenharmony_ci
3248bf80f4bSopenharmony_ci    FT_Face face;
3258bf80f4bSopenharmony_ci    FT_Error err = FT_New_Memory_Face(fontLib_, buf.data(), (FT_Long)buf.size(), index, &face);
3268bf80f4bSopenharmony_ci    if (err) {
3278bf80f4bSopenharmony_ci        CORE_LOG_E("failed to init font face");
3288bf80f4bSopenharmony_ci        return nullptr;
3298bf80f4bSopenharmony_ci    }
3308bf80f4bSopenharmony_ci    if (!face->charmap) {
3318bf80f4bSopenharmony_ci        CORE_LOG_E("failed to init font face, no unicode charmap available");
3328bf80f4bSopenharmony_ci        FT_Done_Face(face);
3338bf80f4bSopenharmony_ci        return nullptr;
3348bf80f4bSopenharmony_ci    }
3358bf80f4bSopenharmony_ci
3368bf80f4bSopenharmony_ci    CORE_ASSERT(face->num_glyphs > 0);
3378bf80f4bSopenharmony_ci
3388bf80f4bSopenharmony_ci    return face;
3398bf80f4bSopenharmony_ci}
3408bf80f4bSopenharmony_ci
3418bf80f4bSopenharmony_ciFontManager::AtlasTexture* FontManager::CreateAtlasTexture(bool color)
3428bf80f4bSopenharmony_ci{
3438bf80f4bSopenharmony_ci    // Access locked from caller already
3448bf80f4bSopenharmony_ci    auto tex = &atlasTextures_.emplace_back();
3458bf80f4bSopenharmony_ci    const ComponentMapping colorSwizzle { CORE_COMPONENT_SWIZZLE_B, CORE_COMPONENT_SWIZZLE_G, CORE_COMPONENT_SWIZZLE_R,
3468bf80f4bSopenharmony_ci        CORE_COMPONENT_SWIZZLE_A }; // BGRA swizzle
3478bf80f4bSopenharmony_ci    const ComponentMapping monoSwizzle { CORE_COMPONENT_SWIZZLE_R, CORE_COMPONENT_SWIZZLE_R, CORE_COMPONENT_SWIZZLE_R,
3488bf80f4bSopenharmony_ci        CORE_COMPONENT_SWIZZLE_R }; // RRRR swizzle
3498bf80f4bSopenharmony_ci    const GpuImageDesc desc {
3508bf80f4bSopenharmony_ci        ImageType::CORE_IMAGE_TYPE_2D,                                            // imageType
3518bf80f4bSopenharmony_ci        ImageViewType::CORE_IMAGE_VIEW_TYPE_2D,                                   // imageViewType
3528bf80f4bSopenharmony_ci        color ? Format::BASE_FORMAT_R8G8B8A8_SRGB : Format::BASE_FORMAT_R8_UNORM, // format
3538bf80f4bSopenharmony_ci        ImageTiling::CORE_IMAGE_TILING_OPTIMAL,                                   // imageTiling
3548bf80f4bSopenharmony_ci        ImageUsageFlagBits::CORE_IMAGE_USAGE_TRANSFER_DST_BIT |
3558bf80f4bSopenharmony_ci            ImageUsageFlagBits::CORE_IMAGE_USAGE_SAMPLED_BIT,                     // usageFlags
3568bf80f4bSopenharmony_ci        MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,            // memoryPropertyFlags
3578bf80f4bSopenharmony_ci        0,                                                                        // ImageCreateFlags
3588bf80f4bSopenharmony_ci        EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS, // EngineImageCreationFlags
3598bf80f4bSopenharmony_ci        FontDefs::ATLAS_SIZE,                                                     // width
3608bf80f4bSopenharmony_ci        FontDefs::ATLAS_SIZE,                                                     // height
3618bf80f4bSopenharmony_ci        1,                                                                        // depth
3628bf80f4bSopenharmony_ci        1,                                                                        // mip count
3638bf80f4bSopenharmony_ci        1,                                                                        // layer count
3648bf80f4bSopenharmony_ci        SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT,                             // sample count
3658bf80f4bSopenharmony_ci        color ? colorSwizzle : monoSwizzle                                        // swizzle
3668bf80f4bSopenharmony_ci    };
3678bf80f4bSopenharmony_ci    auto& gpuResourceManager = renderContext_.GetDevice().GetGpuResourceManager();
3688bf80f4bSopenharmony_ci    tex->handle = gpuResourceManager.Create(desc);
3698bf80f4bSopenharmony_ci    tex->widthLeft = FontDefs::ATLAS_SIZE;
3708bf80f4bSopenharmony_ci    tex->inColor = color;
3718bf80f4bSopenharmony_ci
3728bf80f4bSopenharmony_ci#if defined(FONT_VALIDATION_ENABLED) && (FONT_VALIDATION_ENABLED)
3738bf80f4bSopenharmony_ci    string atlasName = "FontAtlas:";
3748bf80f4bSopenharmony_ci    atlasName += to_string(reinterpret_cast<uintptr_t>(this));
3758bf80f4bSopenharmony_ci    atlasName += ':';
3768bf80f4bSopenharmony_ci    atlasName += to_string(atlasTextures_.size());
3778bf80f4bSopenharmony_ci    tex->name = atlasName;
3788bf80f4bSopenharmony_ci    CORE_LOG_N("Created atlas '%s' gpuHnd: %llx", tex->name.data(), tex->handle.GetHandle().id);
3798bf80f4bSopenharmony_ci#endif
3808bf80f4bSopenharmony_ci
3818bf80f4bSopenharmony_ci    // Clear the atlas as we don't initialize borders when copying glyphs
3828bf80f4bSopenharmony_ci    auto staging = static_cast<IRenderDataStoreDefaultStaging*>(
3838bf80f4bSopenharmony_ci        renderContext_.GetRenderDataStoreManager().GetRenderDataStore(RENDER_DATA_STORE_DEFAULT_STAGING));
3848bf80f4bSopenharmony_ci    ClearColorValue zero { 0.f, 0.f, 0.f, 0.f };
3858bf80f4bSopenharmony_ci    staging->ClearColorImage(tex->handle, zero);
3868bf80f4bSopenharmony_ci    return tex;
3878bf80f4bSopenharmony_ci}
3888bf80f4bSopenharmony_ci
3898bf80f4bSopenharmony_ciint FontManager::UpdateAtlas(FontDefs::Glyph& glyph, const FT_Bitmap& bitmap, bool inColor)
3908bf80f4bSopenharmony_ci{
3918bf80f4bSopenharmony_ci    uint32_t width = bitmap.width + BORDER_WIDTH_X2;
3928bf80f4bSopenharmony_ci    uint32_t height = bitmap.rows + BORDER_WIDTH_X2;
3938bf80f4bSopenharmony_ci
3948bf80f4bSopenharmony_ci    // Find best fit (but larger) column in atlases
3958bf80f4bSopenharmony_ci    uint32_t bestFitAtlas = 0;
3968bf80f4bSopenharmony_ci    uint32_t bestFitColumn = 0;
3978bf80f4bSopenharmony_ci    uint32_t bestFitColumnPos = 0;
3988bf80f4bSopenharmony_ci    uint32_t minDiff = UINT32_MAX;
3998bf80f4bSopenharmony_ci
4008bf80f4bSopenharmony_ci    std::lock_guard writerLock(atlasMutex_);
4018bf80f4bSopenharmony_ci
4028bf80f4bSopenharmony_ci    for (uint32_t i = 0; i < atlasTextures_.size(); ++i) {
4038bf80f4bSopenharmony_ci        auto& atlas = atlasTextures_[i];
4048bf80f4bSopenharmony_ci        if (inColor == atlas.inColor) {
4058bf80f4bSopenharmony_ci            uint32_t colPos = 0;
4068bf80f4bSopenharmony_ci            for (uint32_t col = 0; col < atlas.columns.size(); ++col) {
4078bf80f4bSopenharmony_ci                auto& hdr = atlas.columns[col];
4088bf80f4bSopenharmony_ci                colPos += hdr.colWidth;
4098bf80f4bSopenharmony_ci            }
4108bf80f4bSopenharmony_ci        }
4118bf80f4bSopenharmony_ci    }
4128bf80f4bSopenharmony_ci
4138bf80f4bSopenharmony_ci    if (minDiff <= GLYPH_FIT_THRESHOLD) {
4148bf80f4bSopenharmony_ci        // Close enough
4158bf80f4bSopenharmony_ci        auto& atlas = atlasTextures_[bestFitAtlas];
4168bf80f4bSopenharmony_ci        auto& hdr = atlas.columns[bestFitColumn];
4178bf80f4bSopenharmony_ci        AddGlyphToColumn(glyph, bestFitAtlas, hdr, bitmap, bestFitColumnPos);
4188bf80f4bSopenharmony_ci        return ATLAS_OK;
4198bf80f4bSopenharmony_ci    }
4208bf80f4bSopenharmony_ci
4218bf80f4bSopenharmony_ci    // Need to create new atlas
4228bf80f4bSopenharmony_ci    size_t i = atlasTextures_.size();
4238bf80f4bSopenharmony_ci    auto atlas = CreateAtlasTexture(inColor);
4248bf80f4bSopenharmony_ci    atlas->widthLeft -= width;
4258bf80f4bSopenharmony_ci    auto& hdr = atlas->columns.emplace_back();
4268bf80f4bSopenharmony_ci    hdr.colWidth = static_cast<uint16_t>(width);
4278bf80f4bSopenharmony_ci    hdr.heightLeft = static_cast<uint16_t>(ATLAS_SIZE);
4288bf80f4bSopenharmony_ci    AddGlyphToColumn(glyph, i, hdr, bitmap, 0);
4298bf80f4bSopenharmony_ci    return ATLAS_OK;
4308bf80f4bSopenharmony_ci}
4318bf80f4bSopenharmony_ci
4328bf80f4bSopenharmony_civoid FontManager::UploadPending()
4338bf80f4bSopenharmony_ci{
4348bf80f4bSopenharmony_ci    std::lock_guard writerLock(atlasMutex_);
4358bf80f4bSopenharmony_ci    if (std::all_of(atlasTextures_.cbegin(), atlasTextures_.cend(),
4368bf80f4bSopenharmony_ci        [](const AtlasTexture& atlas) { return atlas.pending.empty(); })) {
4378bf80f4bSopenharmony_ci        return;
4388bf80f4bSopenharmony_ci    }
4398bf80f4bSopenharmony_ci
4408bf80f4bSopenharmony_ci    struct ColumnSize {
4418bf80f4bSopenharmony_ci        uint32_t index;
4428bf80f4bSopenharmony_ci        uint32_t count;
4438bf80f4bSopenharmony_ci        uint16_t width;
4448bf80f4bSopenharmony_ci        uint16_t height;
4458bf80f4bSopenharmony_ci        uint32_t byteSize;
4468bf80f4bSopenharmony_ci    };
4478bf80f4bSopenharmony_ci    BASE_NS::vector<BASE_NS::vector<ColumnSize>> allColumnWidths;
4488bf80f4bSopenharmony_ci    allColumnWidths.reserve(atlasTextures_.size());
4498bf80f4bSopenharmony_ci    uint32_t totalSize = 0U;
4508bf80f4bSopenharmony_ci    for (auto& atlas : atlasTextures_) {
4518bf80f4bSopenharmony_ci        auto& columnWidths = allColumnWidths.emplace_back();
4528bf80f4bSopenharmony_ci        columnWidths.reserve(atlas.pending.size());
4538bf80f4bSopenharmony_ci    }
4548bf80f4bSopenharmony_ci    if (!totalSize) {
4558bf80f4bSopenharmony_ci        return;
4568bf80f4bSopenharmony_ci    }
4578bf80f4bSopenharmony_ci
4588bf80f4bSopenharmony_ci    // create a staging buffer big enough for all the columns
4598bf80f4bSopenharmony_ci    const GpuBufferDesc desc {
4608bf80f4bSopenharmony_ci        BufferUsageFlagBits::CORE_BUFFER_USAGE_TRANSFER_SRC_BIT, // usageFlags
4618bf80f4bSopenharmony_ci        MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
4628bf80f4bSopenharmony_ci            MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT, // memoryPropertyFlags
4638bf80f4bSopenharmony_ci        EngineBufferCreationFlagBits::CORE_ENGINE_BUFFER_CREATION_CREATE_IMMEDIATE |
4648bf80f4bSopenharmony_ci            EngineBufferCreationFlagBits::CORE_ENGINE_BUFFER_CREATION_DEFERRED_DESTROY |
4658bf80f4bSopenharmony_ci            EngineBufferCreationFlagBits::CORE_ENGINE_BUFFER_CREATION_MAP_OUTSIDE_RENDERER, // engineCreationFlags
4668bf80f4bSopenharmony_ci        totalSize,                                                                          // byteSize
4678bf80f4bSopenharmony_ci        BASE_NS::Format::BASE_FORMAT_UNDEFINED,                                             // format
4688bf80f4bSopenharmony_ci    };
4698bf80f4bSopenharmony_ci    auto& gpuResMan = renderContext_.GetDevice().GetGpuResourceManager();
4708bf80f4bSopenharmony_ci    auto bufferHandle = gpuResMan.Create(desc);
4718bf80f4bSopenharmony_ci    auto* ptr = static_cast<uint8_t*>(gpuResMan.MapBufferMemory(bufferHandle));
4728bf80f4bSopenharmony_ci    if (!ptr) {
4738bf80f4bSopenharmony_ci        return;
4748bf80f4bSopenharmony_ci    }
4758bf80f4bSopenharmony_ci    auto buffer = array_view(ptr, totalSize);
4768bf80f4bSopenharmony_ci    std::fill(buffer.begin(), buffer.end(), uint8_t(0u));
4778bf80f4bSopenharmony_ci}
4788bf80f4bSopenharmony_ci
4798bf80f4bSopenharmony_civoid FontManager::AddGlyphToColumn(
4808bf80f4bSopenharmony_ci    Glyph& glyph, size_t atlasIndex, ColumnHeader& hdr, const FT_Bitmap& bitmap, uint32_t columnX)
4818bf80f4bSopenharmony_ci{
4828bf80f4bSopenharmony_ci    uint32_t width = bitmap.width;
4838bf80f4bSopenharmony_ci    uint32_t height = bitmap.rows;
4848bf80f4bSopenharmony_ci
4858bf80f4bSopenharmony_ci    uint32_t x = columnX + BORDER_WIDTH;
4868bf80f4bSopenharmony_ci    uint32_t y = ATLAS_SIZE - hdr.heightLeft + BORDER_WIDTH;
4878bf80f4bSopenharmony_ci
4888bf80f4bSopenharmony_ci    hdr.heightLeft -= static_cast<uint16_t>(height + BORDER_WIDTH_X2);
4898bf80f4bSopenharmony_ci
4908bf80f4bSopenharmony_ci    glyph.atlas.index = static_cast<uint16_t>(atlasIndex);
4918bf80f4bSopenharmony_ci    glyph.atlas.rect.x = static_cast<uint16_t>(x);
4928bf80f4bSopenharmony_ci    glyph.atlas.rect.y = static_cast<uint16_t>(y);
4938bf80f4bSopenharmony_ci    glyph.atlas.rect.w = static_cast<uint16_t>(width);
4948bf80f4bSopenharmony_ci    glyph.atlas.rect.h = static_cast<uint16_t>(height);
4958bf80f4bSopenharmony_ci
4968bf80f4bSopenharmony_ci    // Access locked by caller
4978bf80f4bSopenharmony_ci    uint32_t bpp = (atlasTextures_[atlasIndex].inColor ? 4u : 1u);
4988bf80f4bSopenharmony_ci
4998bf80f4bSopenharmony_ci    if (width > 0 && height > 0 && bitmap.pitch / bpp >= width) {
5008bf80f4bSopenharmony_ci        atlasTextures_[atlasIndex].pending.push_back({
5018bf80f4bSopenharmony_ci            static_cast<uint16_t>(x),
5028bf80f4bSopenharmony_ci            static_cast<uint16_t>(y),
5038bf80f4bSopenharmony_ci            static_cast<uint16_t>(width),
5048bf80f4bSopenharmony_ci            static_cast<uint16_t>(height),
5058bf80f4bSopenharmony_ci            { bitmap.buffer, bitmap.buffer + bitmap.pitch * bitmap.rows },
5068bf80f4bSopenharmony_ci        });
5078bf80f4bSopenharmony_ci    }
5088bf80f4bSopenharmony_ci}
5098bf80f4bSopenharmony_ci
5108bf80f4bSopenharmony_civoid FontManager::Gc(uint64_t uid, FontBuffer* data)
5118bf80f4bSopenharmony_ci{
5128bf80f4bSopenharmony_ci    // Check if file data cache has this font
5138bf80f4bSopenharmony_ci    std::lock_guard writerLock(fontBuffersMutex_);
5148bf80f4bSopenharmony_ci
5158bf80f4bSopenharmony_ci    if (!fontBuffers_.erase(uid)) {
5168bf80f4bSopenharmony_ci        for (auto it = fontBuffers_.cbegin(); it != fontBuffers_.cend();) {
5178bf80f4bSopenharmony_ci            if (it->second.expired()) {
5188bf80f4bSopenharmony_ci                fontBuffers_.erase(it);
5198bf80f4bSopenharmony_ci            } else {
5208bf80f4bSopenharmony_ci                ++it;
5218bf80f4bSopenharmony_ci            }
5228bf80f4bSopenharmony_ci        }
5238bf80f4bSopenharmony_ci    }
5248bf80f4bSopenharmony_ci    if (fontBuffers_.empty()) {
5258bf80f4bSopenharmony_ci        FlushCaches();
5268bf80f4bSopenharmony_ci    }
5278bf80f4bSopenharmony_ci}
5288bf80f4bSopenharmony_ci
5298bf80f4bSopenharmony_ciconst CORE_NS::IInterface* FontManager::GetInterface(const BASE_NS::Uid& uid) const
5308bf80f4bSopenharmony_ci{
5318bf80f4bSopenharmony_ci    if (uid == CORE_NS::IInterface::UID) {
5328bf80f4bSopenharmony_ci        return this;
5338bf80f4bSopenharmony_ci    }
5348bf80f4bSopenharmony_ci    if (uid == IFontManager::UID) {
5358bf80f4bSopenharmony_ci        return this;
5368bf80f4bSopenharmony_ci    }
5378bf80f4bSopenharmony_ci    return nullptr;
5388bf80f4bSopenharmony_ci}
5398bf80f4bSopenharmony_ci
5408bf80f4bSopenharmony_ciCORE_NS::IInterface* FontManager::GetInterface(const BASE_NS::Uid& uid)
5418bf80f4bSopenharmony_ci{
5428bf80f4bSopenharmony_ci    if (uid == CORE_NS::IInterface::UID) {
5438bf80f4bSopenharmony_ci        return this;
5448bf80f4bSopenharmony_ci    }
5458bf80f4bSopenharmony_ci    if (uid == IFontManager::UID) {
5468bf80f4bSopenharmony_ci        return this;
5478bf80f4bSopenharmony_ci    }
5488bf80f4bSopenharmony_ci    return nullptr;
5498bf80f4bSopenharmony_ci}
5508bf80f4bSopenharmony_ci
5518bf80f4bSopenharmony_civoid FontManager::Ref()
5528bf80f4bSopenharmony_ci{
5538bf80f4bSopenharmony_ci    refcnt_.fetch_add(1, std::memory_order_relaxed);
5548bf80f4bSopenharmony_ci}
5558bf80f4bSopenharmony_ci
5568bf80f4bSopenharmony_civoid FontManager::Unref()
5578bf80f4bSopenharmony_ci{
5588bf80f4bSopenharmony_ci    if (refcnt_.fetch_sub(1, std::memory_order_release) == 1) {
5598bf80f4bSopenharmony_ci        std::atomic_thread_fence(std::memory_order_acquire);
5608bf80f4bSopenharmony_ci        CORE_LOG_N("delete FontManager %p", this);
5618bf80f4bSopenharmony_ci        delete this;
5628bf80f4bSopenharmony_ci    }
5638bf80f4bSopenharmony_ci}
5648bf80f4bSopenharmony_ciFONT_END_NAMESPACE()
565