1 /* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef UTIL__FONT_MANAGER_H 17 #define UTIL__FONT_MANAGER_H 18 19 #include <atomic> 20 #include <ft2build.h> 21 #include <memory> 22 #include <shared_mutex> 23 #include FT_FREETYPE_H 24 #include <freetype/ftglyph.h> 25 26 #include <base/containers/unordered_map.h> 27 #include <font/intf_font_manager.h> 28 #include <render/resource_handle.h> 29 30 #include "font_defs.h" 31 32 RENDER_BEGIN_NAMESPACE() 33 class IRenderContext; 34 RENDER_END_NAMESPACE() 35 36 FONT_BEGIN_NAMESPACE() 37 class FontBuffer; 38 39 class FontManager final : public IFontManager { 40 public: 41 explicit FontManager(RENDER_NS::IRenderContext& context); 42 ~FontManager(); 43 44 FontManager(FontManager const&) = delete; 45 FontManager& operator=(FontManager const&) = delete; 46 47 // IFontManager 48 uint32_t GetGlyphIndex(const TypeFace&, uint32_t code) override; 49 50 BASE_NS::array_view<const TypeFace> GetTypeFaces() const override; 51 inline const TypeFace* GetTypeFace(BASE_NS::string_view name) override 52 { 53 return GetTypeFace(name, nullptr); 54 } 55 const TypeFace* GetTypeFace(BASE_NS::string_view name, BASE_NS::string_view styleName) override; 56 BASE_NS::vector<TypeFace> GetTypeFaces(BASE_NS::string_view filePath) override; 57 BASE_NS::vector<TypeFace> GetTypeFaces(BASE_NS::array_view<const BASE_NS::string_view> lookupDirs) override; 58 59 IFont::Ptr CreateFont(const TypeFace& typeface) override; 60 IFont::Ptr CreateFontFromMemory(const TypeFace& typeface, const BASE_NS::vector<uint8_t>& fontData) override; 61 62 void FlushCaches() override; 63 64 // IInterface 65 const CORE_NS::IInterface* GetInterface(const BASE_NS::Uid& uid) const override; 66 CORE_NS::IInterface* GetInterface(const BASE_NS::Uid& uid) override; 67 void Ref() override; 68 void Unref() override; 69 70 void Gc(uint64_t uid, FontBuffer* data); 71 72 FT_Face OpenFtFace(BASE_NS::array_view<const uint8_t> buf, FT_Long index); 73 74 // Called by FontData to request atlas slots 75 /* 76 * fit glyph to atlas 77 * 78 * @ret: -1 failure; 0 success; 1 atlas reset 79 * 80 */ 81 int UpdateAtlas(FontDefs::Glyph& glyph, const FT_Bitmap&, bool inColor); 82 83 void UploadPending(); 84 85 /* atlas partitioning: 86 * 87 * | 10 px | 24 px | 12 px | NN px | (sizes are for example) 88 * +-------+-------+-------+-------+ 89 * | A | a | F | E | <== row 0 90 * | a | C | f | D | <== row 1 91 * ... ... ... ... <== row N 92 * ... ... ... ... 93 * ... ... ... ... 94 * 95 * Atlas info contains info on free width left and list of columns which have info on their width and free height 96 * left for that column. 97 * 98 * Filling algorithm works like this: 99 * - checks if the color formats match (mono vs color font) and if not skips that atlas 100 * - goes through all columns looking for an exact width match with enough free height left and uses that if found 101 * - simultaneously keeps track of the closest width column that has enough free height left 102 * - if no exact fit is found, checks if the closes width fit is close enough (GLYPH_FIT_THRESHOLD pixels) and uses 103 * that 104 * - if no close enough match is found, and atlas has enough free width left, creates a new column and puts the 105 * glyph as first element there 106 * - if none of the above conditions are fullfilled, creates a new atlas texture and creates a new column and puts 107 * the glyph there 108 * 109 * In pseudo code: 110 * for ( atlas in atlases ) { 111 * if ( atlas format is glyph format ) { 112 * for ( column in atlas columns ) { 113 * if ( column has glyph height free and is wider or equal to glyph width ) { 114 * if ( column width exactly glyph width ) { 115 * insert glyph to this column and return 116 * } else { 117 * update closest column width 118 * } 119 * } 120 * } 121 * if ( closest column width is at most GLYPH_FIT_THRESHOLD pixels ) { 122 * insert glyph to closest width column and return 123 * } 124 * if ( atlas has glyph width free left ) { 125 * allocate new column, insert the glyph and return 126 * } 127 * } 128 * } 129 * allocate new atlas, allocate first column, insert glyph and return 130 * 131 * Initially there are no atlases available so the first glyph creates one as it falls to the end right away. Same 132 * happens when color format changes for the first time. 133 */ 134 struct ColumnHeader { 135 uint16_t colWidth; 136 uint16_t heightLeft; 137 }; 138 struct PendingGlyph { 139 uint16_t posX; 140 uint16_t posY; 141 uint16_t width; 142 uint16_t height; 143 BASE_NS::vector<uint8_t> data; 144 }; 145 struct AtlasTexture { 146 RENDER_NS::RenderHandleReference handle; 147 BASE_NS::vector<ColumnHeader> columns; 148 BASE_NS::vector<PendingGlyph> pending; 149 uint32_t widthLeft; 150 bool inColor; 151 #if defined(FONT_VALIDATION_ENABLED) && (FONT_VALIDATION_ENABLED) 152 BASE_NS::string name; 153 #endif 154 }; 155 GetAtlas(size_t index)156 AtlasTexture* GetAtlas(size_t index) 157 { 158 std::shared_lock readerLock(atlasMutex_); 159 160 if (index >= atlasTextures_.size()) { 161 return nullptr; 162 } 163 return &atlasTextures_[index]; 164 } 165 166 private: 167 void GetTypeFacesByFile(BASE_NS::vector<TypeFace>& typeFaces, BASE_NS::string_view path); 168 void GetTypeFacesByDir(BASE_NS::vector<TypeFace>& typeFaces, BASE_NS::string_view path); 169 170 std::shared_ptr<FontBuffer> CreateFontBuffer(const TypeFace& typeFace); 171 172 // Atlas manager 173 AtlasTexture* CreateAtlasTexture(bool color); 174 void AddGlyphToColumn( 175 FontDefs::Glyph& glyph, size_t atlasIndex, ColumnHeader& hdr, const FT_Bitmap& bitmap, uint32_t columnX); 176 177 std::atomic_uint32_t refcnt_ { 0 }; 178 179 RENDER_NS::IRenderContext& renderContext_; 180 181 FT_Library fontLib_; 182 183 std::shared_mutex fontBuffersMutex_; // mutex for file data cache access 184 BASE_NS::unordered_map<uint64_t, std::weak_ptr<FontBuffer>> fontBuffers_; 185 BASE_NS::vector<TypeFace> typeFaces_; 186 187 std::shared_mutex atlasMutex_; // mutex for atlas texture access 188 BASE_NS::vector<AtlasTexture> atlasTextures_; 189 }; 190 191 FONT_END_NAMESPACE() 192 193 #endif // UTIL__FONT_MANAGER_H 194