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; GetTypeFace(BASE_NS::string_view name)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 void UploadPending() override; 65 66 // IInterface 67 const CORE_NS::IInterface* GetInterface(const BASE_NS::Uid& uid) const override; 68 CORE_NS::IInterface* GetInterface(const BASE_NS::Uid& uid) override; 69 void Ref() override; 70 void Unref() override; 71 72 void Gc(uint64_t uid, FontBuffer* data); 73 74 bool IsFont(BASE_NS::string_view uri); 75 76 FT_Face OpenFtFace(BASE_NS::array_view<const uint8_t> buf, FT_Long index); 77 78 // Called by FontData to request atlas slots 79 /* 80 * fit glyph to atlas 81 * 82 * @ret: -1 failure; 0 success; 1 atlas reset 83 * 84 */ 85 int UpdateAtlas(FontDefs::Glyph& glyph, const FT_Bitmap&, bool inColor); 86 87 /* atlas partitioning: 88 * 89 * | 10 px | 24 px | 12 px | NN px | (sizes are for example) 90 * +-------+-------+-------+-------+ 91 * | A | a | F | E | <== row 0 92 * | a | C | f | D | <== row 1 93 * ... ... ... ... <== row N 94 * ... ... ... ... 95 * ... ... ... ... 96 * 97 * Atlas info contains info on free width left and list of columns which have info on their width and free height 98 * left for that column. 99 * 100 * Filling algorithm works like this: 101 * - checks if the color formats match (mono vs color font) and if not skips that atlas 102 * - goes through all columns looking for an exact width match with enough free height left and uses that if found 103 * - simultaneously keeps track of the closest width column that has enough free height left 104 * - if no exact fit is found, checks if the closes width fit is close enough (GLYPH_FIT_THRESHOLD pixels) and uses 105 * that 106 * - if no close enough match is found, and atlas has enough free width left, creates a new column and puts the 107 * glyph as first element there 108 * - if none of the above conditions are fullfilled, creates a new atlas texture and creates a new column and puts 109 * the glyph there 110 * 111 * In pseudo code: 112 * for ( atlas in atlases ) { 113 * if ( atlas format is glyph format ) { 114 * for ( column in atlas columns ) { 115 * if ( column has glyph height free and is wider or equal to glyph width ) { 116 * if ( column width exactly glyph width ) { 117 * insert glyph to this column and return 118 * } else { 119 * update closest column width 120 * } 121 * } 122 * } 123 * if ( closest column width is at most GLYPH_FIT_THRESHOLD pixels ) { 124 * insert glyph to closest width column and return 125 * } 126 * if ( atlas has glyph width free left ) { 127 * allocate new column, insert the glyph and return 128 * } 129 * } 130 * } 131 * allocate new atlas, allocate first column, insert glyph and return 132 * 133 * Initially there are no atlases available so the first glyph creates one as it falls to the end right away. Same 134 * happens when color format changes for the first time. 135 */ 136 struct ColumnHeader { 137 uint16_t colWidth; 138 uint16_t heightLeft; 139 }; 140 struct PendingGlyph { 141 uint16_t posX; 142 uint16_t posY; 143 uint16_t width; 144 uint16_t height; 145 BASE_NS::vector<uint8_t> data; 146 }; 147 struct AtlasTexture { 148 RENDER_NS::RenderHandleReference handle; 149 BASE_NS::vector<ColumnHeader> columns; 150 BASE_NS::vector<PendingGlyph> pending; 151 uint32_t widthLeft; 152 bool inColor; 153 #if defined(FONT_VALIDATION_ENABLED) && (FONT_VALIDATION_ENABLED) 154 BASE_NS::string name; 155 #endif 156 }; 157 GetAtlas(size_t index)158 AtlasTexture* GetAtlas(size_t index) 159 { 160 std::shared_lock readerLock(atlasMutex_); 161 162 if (index >= atlasTextures_.size()) { 163 return nullptr; 164 } 165 return &atlasTextures_[index]; 166 } 167 168 private: 169 bool OpenFtFace(BASE_NS::string_view uri, FT_Long index, FT_Face* face); 170 171 void GetTypeFacesByFile(BASE_NS::vector<TypeFace>& typeFaces, BASE_NS::string_view path); 172 void GetTypeFacesByDir(BASE_NS::vector<TypeFace>& typeFaces, BASE_NS::string_view path); 173 174 std::shared_ptr<FontBuffer> CreateFontBuffer(const TypeFace& typeFace); 175 176 // Atlas manager 177 AtlasTexture* CreateAtlasTexture(bool color); 178 void AddGlyphToColumn( 179 FontDefs::Glyph& glyph, size_t atlasIndex, ColumnHeader& hdr, const FT_Bitmap& bitmap, uint32_t columnX); 180 181 std::atomic_uint32_t refcnt_ { 0 }; 182 183 RENDER_NS::IRenderContext& renderContext_; 184 185 FT_Library fontLib_; 186 187 std::shared_mutex fontBuffersMutex_; // mutex for file data cache access 188 BASE_NS::unordered_map<uint64_t, std::weak_ptr<FontBuffer>> fontBuffers_; 189 BASE_NS::vector<TypeFace> typeFaces_; 190 191 std::shared_mutex atlasMutex_; // mutex for atlas texture access 192 BASE_NS::vector<AtlasTexture> atlasTextures_; 193 }; 194 195 FONT_END_NAMESPACE() 196 197 #endif // UTIL__FONT_MANAGER_H 198