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#ifndef UTIL__FONT_MANAGER_H 178bf80f4bSopenharmony_ci#define UTIL__FONT_MANAGER_H 188bf80f4bSopenharmony_ci 198bf80f4bSopenharmony_ci#include <atomic> 208bf80f4bSopenharmony_ci#include <ft2build.h> 218bf80f4bSopenharmony_ci#include <memory> 228bf80f4bSopenharmony_ci#include <shared_mutex> 238bf80f4bSopenharmony_ci#include FT_FREETYPE_H 248bf80f4bSopenharmony_ci#include <freetype/ftglyph.h> 258bf80f4bSopenharmony_ci 268bf80f4bSopenharmony_ci#include <base/containers/unordered_map.h> 278bf80f4bSopenharmony_ci#include <font/intf_font_manager.h> 288bf80f4bSopenharmony_ci#include <render/resource_handle.h> 298bf80f4bSopenharmony_ci 308bf80f4bSopenharmony_ci#include "font_defs.h" 318bf80f4bSopenharmony_ci 328bf80f4bSopenharmony_ciRENDER_BEGIN_NAMESPACE() 338bf80f4bSopenharmony_ciclass IRenderContext; 348bf80f4bSopenharmony_ciRENDER_END_NAMESPACE() 358bf80f4bSopenharmony_ci 368bf80f4bSopenharmony_ciFONT_BEGIN_NAMESPACE() 378bf80f4bSopenharmony_ciclass FontBuffer; 388bf80f4bSopenharmony_ci 398bf80f4bSopenharmony_ciclass FontManager final : public IFontManager { 408bf80f4bSopenharmony_cipublic: 418bf80f4bSopenharmony_ci explicit FontManager(RENDER_NS::IRenderContext& context); 428bf80f4bSopenharmony_ci ~FontManager(); 438bf80f4bSopenharmony_ci 448bf80f4bSopenharmony_ci FontManager(FontManager const&) = delete; 458bf80f4bSopenharmony_ci FontManager& operator=(FontManager const&) = delete; 468bf80f4bSopenharmony_ci 478bf80f4bSopenharmony_ci // IFontManager 488bf80f4bSopenharmony_ci uint32_t GetGlyphIndex(const TypeFace&, uint32_t code) override; 498bf80f4bSopenharmony_ci 508bf80f4bSopenharmony_ci BASE_NS::array_view<const TypeFace> GetTypeFaces() const override; 518bf80f4bSopenharmony_ci inline const TypeFace* GetTypeFace(BASE_NS::string_view name) override 528bf80f4bSopenharmony_ci { 538bf80f4bSopenharmony_ci return GetTypeFace(name, nullptr); 548bf80f4bSopenharmony_ci } 558bf80f4bSopenharmony_ci const TypeFace* GetTypeFace(BASE_NS::string_view name, BASE_NS::string_view styleName) override; 568bf80f4bSopenharmony_ci BASE_NS::vector<TypeFace> GetTypeFaces(BASE_NS::string_view filePath) override; 578bf80f4bSopenharmony_ci BASE_NS::vector<TypeFace> GetTypeFaces(BASE_NS::array_view<const BASE_NS::string_view> lookupDirs) override; 588bf80f4bSopenharmony_ci 598bf80f4bSopenharmony_ci IFont::Ptr CreateFont(const TypeFace& typeface) override; 608bf80f4bSopenharmony_ci IFont::Ptr CreateFontFromMemory(const TypeFace& typeface, const BASE_NS::vector<uint8_t>& fontData) override; 618bf80f4bSopenharmony_ci 628bf80f4bSopenharmony_ci void FlushCaches() override; 638bf80f4bSopenharmony_ci 648bf80f4bSopenharmony_ci // IInterface 658bf80f4bSopenharmony_ci const CORE_NS::IInterface* GetInterface(const BASE_NS::Uid& uid) const override; 668bf80f4bSopenharmony_ci CORE_NS::IInterface* GetInterface(const BASE_NS::Uid& uid) override; 678bf80f4bSopenharmony_ci void Ref() override; 688bf80f4bSopenharmony_ci void Unref() override; 698bf80f4bSopenharmony_ci 708bf80f4bSopenharmony_ci void Gc(uint64_t uid, FontBuffer* data); 718bf80f4bSopenharmony_ci 728bf80f4bSopenharmony_ci FT_Face OpenFtFace(BASE_NS::array_view<const uint8_t> buf, FT_Long index); 738bf80f4bSopenharmony_ci 748bf80f4bSopenharmony_ci // Called by FontData to request atlas slots 758bf80f4bSopenharmony_ci /* 768bf80f4bSopenharmony_ci * fit glyph to atlas 778bf80f4bSopenharmony_ci * 788bf80f4bSopenharmony_ci * @ret: -1 failure; 0 success; 1 atlas reset 798bf80f4bSopenharmony_ci * 808bf80f4bSopenharmony_ci */ 818bf80f4bSopenharmony_ci int UpdateAtlas(FontDefs::Glyph& glyph, const FT_Bitmap&, bool inColor); 828bf80f4bSopenharmony_ci 838bf80f4bSopenharmony_ci void UploadPending(); 848bf80f4bSopenharmony_ci 858bf80f4bSopenharmony_ci /* atlas partitioning: 868bf80f4bSopenharmony_ci * 878bf80f4bSopenharmony_ci * | 10 px | 24 px | 12 px | NN px | (sizes are for example) 888bf80f4bSopenharmony_ci * +-------+-------+-------+-------+ 898bf80f4bSopenharmony_ci * | A | a | F | E | <== row 0 908bf80f4bSopenharmony_ci * | a | C | f | D | <== row 1 918bf80f4bSopenharmony_ci * ... ... ... ... <== row N 928bf80f4bSopenharmony_ci * ... ... ... ... 938bf80f4bSopenharmony_ci * ... ... ... ... 948bf80f4bSopenharmony_ci * 958bf80f4bSopenharmony_ci * Atlas info contains info on free width left and list of columns which have info on their width and free height 968bf80f4bSopenharmony_ci * left for that column. 978bf80f4bSopenharmony_ci * 988bf80f4bSopenharmony_ci * Filling algorithm works like this: 998bf80f4bSopenharmony_ci * - checks if the color formats match (mono vs color font) and if not skips that atlas 1008bf80f4bSopenharmony_ci * - goes through all columns looking for an exact width match with enough free height left and uses that if found 1018bf80f4bSopenharmony_ci * - simultaneously keeps track of the closest width column that has enough free height left 1028bf80f4bSopenharmony_ci * - if no exact fit is found, checks if the closes width fit is close enough (GLYPH_FIT_THRESHOLD pixels) and uses 1038bf80f4bSopenharmony_ci * that 1048bf80f4bSopenharmony_ci * - if no close enough match is found, and atlas has enough free width left, creates a new column and puts the 1058bf80f4bSopenharmony_ci * glyph as first element there 1068bf80f4bSopenharmony_ci * - if none of the above conditions are fullfilled, creates a new atlas texture and creates a new column and puts 1078bf80f4bSopenharmony_ci * the glyph there 1088bf80f4bSopenharmony_ci * 1098bf80f4bSopenharmony_ci * In pseudo code: 1108bf80f4bSopenharmony_ci * for ( atlas in atlases ) { 1118bf80f4bSopenharmony_ci * if ( atlas format is glyph format ) { 1128bf80f4bSopenharmony_ci * for ( column in atlas columns ) { 1138bf80f4bSopenharmony_ci * if ( column has glyph height free and is wider or equal to glyph width ) { 1148bf80f4bSopenharmony_ci * if ( column width exactly glyph width ) { 1158bf80f4bSopenharmony_ci * insert glyph to this column and return 1168bf80f4bSopenharmony_ci * } else { 1178bf80f4bSopenharmony_ci * update closest column width 1188bf80f4bSopenharmony_ci * } 1198bf80f4bSopenharmony_ci * } 1208bf80f4bSopenharmony_ci * } 1218bf80f4bSopenharmony_ci * if ( closest column width is at most GLYPH_FIT_THRESHOLD pixels ) { 1228bf80f4bSopenharmony_ci * insert glyph to closest width column and return 1238bf80f4bSopenharmony_ci * } 1248bf80f4bSopenharmony_ci * if ( atlas has glyph width free left ) { 1258bf80f4bSopenharmony_ci * allocate new column, insert the glyph and return 1268bf80f4bSopenharmony_ci * } 1278bf80f4bSopenharmony_ci * } 1288bf80f4bSopenharmony_ci * } 1298bf80f4bSopenharmony_ci * allocate new atlas, allocate first column, insert glyph and return 1308bf80f4bSopenharmony_ci * 1318bf80f4bSopenharmony_ci * Initially there are no atlases available so the first glyph creates one as it falls to the end right away. Same 1328bf80f4bSopenharmony_ci * happens when color format changes for the first time. 1338bf80f4bSopenharmony_ci */ 1348bf80f4bSopenharmony_ci struct ColumnHeader { 1358bf80f4bSopenharmony_ci uint16_t colWidth; 1368bf80f4bSopenharmony_ci uint16_t heightLeft; 1378bf80f4bSopenharmony_ci }; 1388bf80f4bSopenharmony_ci struct PendingGlyph { 1398bf80f4bSopenharmony_ci uint16_t posX; 1408bf80f4bSopenharmony_ci uint16_t posY; 1418bf80f4bSopenharmony_ci uint16_t width; 1428bf80f4bSopenharmony_ci uint16_t height; 1438bf80f4bSopenharmony_ci BASE_NS::vector<uint8_t> data; 1448bf80f4bSopenharmony_ci }; 1458bf80f4bSopenharmony_ci struct AtlasTexture { 1468bf80f4bSopenharmony_ci RENDER_NS::RenderHandleReference handle; 1478bf80f4bSopenharmony_ci BASE_NS::vector<ColumnHeader> columns; 1488bf80f4bSopenharmony_ci BASE_NS::vector<PendingGlyph> pending; 1498bf80f4bSopenharmony_ci uint32_t widthLeft; 1508bf80f4bSopenharmony_ci bool inColor; 1518bf80f4bSopenharmony_ci#if defined(FONT_VALIDATION_ENABLED) && (FONT_VALIDATION_ENABLED) 1528bf80f4bSopenharmony_ci BASE_NS::string name; 1538bf80f4bSopenharmony_ci#endif 1548bf80f4bSopenharmony_ci }; 1558bf80f4bSopenharmony_ci 1568bf80f4bSopenharmony_ci AtlasTexture* GetAtlas(size_t index) 1578bf80f4bSopenharmony_ci { 1588bf80f4bSopenharmony_ci std::shared_lock readerLock(atlasMutex_); 1598bf80f4bSopenharmony_ci 1608bf80f4bSopenharmony_ci if (index >= atlasTextures_.size()) { 1618bf80f4bSopenharmony_ci return nullptr; 1628bf80f4bSopenharmony_ci } 1638bf80f4bSopenharmony_ci return &atlasTextures_[index]; 1648bf80f4bSopenharmony_ci } 1658bf80f4bSopenharmony_ci 1668bf80f4bSopenharmony_ciprivate: 1678bf80f4bSopenharmony_ci void GetTypeFacesByFile(BASE_NS::vector<TypeFace>& typeFaces, BASE_NS::string_view path); 1688bf80f4bSopenharmony_ci void GetTypeFacesByDir(BASE_NS::vector<TypeFace>& typeFaces, BASE_NS::string_view path); 1698bf80f4bSopenharmony_ci 1708bf80f4bSopenharmony_ci std::shared_ptr<FontBuffer> CreateFontBuffer(const TypeFace& typeFace); 1718bf80f4bSopenharmony_ci 1728bf80f4bSopenharmony_ci // Atlas manager 1738bf80f4bSopenharmony_ci AtlasTexture* CreateAtlasTexture(bool color); 1748bf80f4bSopenharmony_ci void AddGlyphToColumn( 1758bf80f4bSopenharmony_ci FontDefs::Glyph& glyph, size_t atlasIndex, ColumnHeader& hdr, const FT_Bitmap& bitmap, uint32_t columnX); 1768bf80f4bSopenharmony_ci 1778bf80f4bSopenharmony_ci std::atomic_uint32_t refcnt_ { 0 }; 1788bf80f4bSopenharmony_ci 1798bf80f4bSopenharmony_ci RENDER_NS::IRenderContext& renderContext_; 1808bf80f4bSopenharmony_ci 1818bf80f4bSopenharmony_ci FT_Library fontLib_; 1828bf80f4bSopenharmony_ci 1838bf80f4bSopenharmony_ci std::shared_mutex fontBuffersMutex_; // mutex for file data cache access 1848bf80f4bSopenharmony_ci BASE_NS::unordered_map<uint64_t, std::weak_ptr<FontBuffer>> fontBuffers_; 1858bf80f4bSopenharmony_ci BASE_NS::vector<TypeFace> typeFaces_; 1868bf80f4bSopenharmony_ci 1878bf80f4bSopenharmony_ci std::shared_mutex atlasMutex_; // mutex for atlas texture access 1888bf80f4bSopenharmony_ci BASE_NS::vector<AtlasTexture> atlasTextures_; 1898bf80f4bSopenharmony_ci}; 1908bf80f4bSopenharmony_ci 1918bf80f4bSopenharmony_ciFONT_END_NAMESPACE() 1928bf80f4bSopenharmony_ci 1938bf80f4bSopenharmony_ci#endif // UTIL__FONT_MANAGER_H 194