• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "face_data.h"
17 
18 #include <algorithm>
19 #include <freetype/ftbitmap.h>
20 #include <freetype/ftsizes.h>
21 
22 #include <core/log.h>
23 
24 #include "font_buffer.h"
25 #include "font_data.h"
26 #include "font_manager.h"
27 
28 using namespace BASE_NS;
29 
30 FONT_BEGIN_NAMESPACE()
31 
32 using namespace FontDefs;
33 
FaceData(std::shared_ptr<FontBuffer> buf,FT_Face ftFace)34 FaceData::FaceData(std::shared_ptr<FontBuffer> buf, FT_Face ftFace) : fontBuffer_(buf), face_(ftFace) {}
35 
~FaceData()36 FaceData::~FaceData()
37 {
38     {
39         std::lock_guard writerLock(mutex_);
40         // FontData must be destroyed first as it has a FT_Size which is used by FT_Face.
41         datas_.clear();
42         FT_Done_Face(face_);
43     }
44     fontBuffer_->Gc();
45 }
46 
GetFontManager() const47 FontManager& FaceData::GetFontManager() const
48 {
49     return *(fontBuffer_->fontManager);
50 }
51 
CreateFontData(float sizeInPt,uint16_t xDpi,uint16_t yDpi,bool sdf)52 FontData* FaceData::CreateFontData(float sizeInPt, uint16_t xDpi, uint16_t yDpi, bool sdf)
53 {
54     const FT_Pos pixelSize26Dot6 = FloatToFTPos(sizeInPt * yDpi / 72.f); // 72.0 : param
55     const int64_t pixelSize = (pixelSize26Dot6 >> 6) | (sdf ? (1ll << 32) : 0); // 6 32 : param
56 
57     {
58         std::shared_lock readerLock(mutex_);
59         if (auto it = std::find_if(
60             datas_.cbegin(), datas_.cend(), [pixelSize](const Data& data) { return data.pixelSize == pixelSize; });
61             it != datas_.cend()) {
62             return it->fontData.get();
63         }
64     }
65 
66     std::lock_guard writerLock(mutex_);
67     if (auto it = std::find_if(
68         datas_.cbegin(), datas_.cend(), [pixelSize](const Data& data) { return data.pixelSize == pixelSize; });
69         it != datas_.cend()) {
70         return it->fontData.get();
71     }
72 
73     auto fontData = FontData::CreateFromFaceData(weak_from_this(), sdf);
74     if (!fontData) {
75         return nullptr;
76     }
77 
78     FT_Error err = FT_Err_Ok;
79     if (FT_IS_SCALABLE(face_)) {
80         err = FT_Set_Char_Size(face_, 0, FloatToFTPos(sizeInPt), xDpi, yDpi);
81     } else if (FT_HAS_FIXED_SIZES(face_)) {
82         auto* sizes = face_->available_sizes;
83         int closestIdx = 0;
84         auto smallestDiff = std::abs(sizes[0].y_ppem - pixelSize26Dot6);
85         if (smallestDiff > 0) {
86             for (FT_Int i = 1; i < face_->num_fixed_sizes; i++) {
87                 auto diff = std::abs(sizes[i].y_ppem - pixelSize26Dot6);
88                 if (diff < smallestDiff) {
89                     smallestDiff = diff;
90                     closestIdx = i;
91                     if (!smallestDiff) { // exact
92                         break;
93                     }
94                 }
95             }
96             if (smallestDiff) {
97                 CORE_LOG_N("use of closest match for bitmap font, request: %dpx , selected: %dpx",
98                     pixelSize26Dot6 >> 6, sizes[closestIdx].y_ppem >> 6); // 6 : param
99             }
100         }
101         err = FT_Select_Size(face_, closestIdx);
102     } else {
103         CORE_LOG_E("face not scallable and no bitmap size available");
104     }
105 
106     if (err) {
107         CORE_LOG_E("failed to select font face size: %d", err);
108         return nullptr;
109     }
110 
111     auto fontDataPtr = fontData.get();
112     datas_.push_back(Data { pixelSize, std::move(fontData) });
113 
114     CORE_LOG_N("create FontData PT: %f dpi: %d (pix: %d, yppem: %d, h: %d) %p", sizeInPt, yDpi, pixelSize,
115         fontDataPtr->sizeData_->metrics.y_ppem, fontDataPtr->sizeData_->metrics.height >> 6, this); // 6 : param
116     return fontDataPtr;
117 }
118 
UpdateGlyph(bool sdf,FT_Size ftSize,uint32_t glyphIndex,FontDefs::Glyph & glyph)119 int FaceData::UpdateGlyph(bool sdf, FT_Size ftSize, uint32_t glyphIndex, FontDefs::Glyph& glyph)
120 {
121     std::lock_guard writerLock(mutex_);
122 
123     // if face's active size is different, try to activate this one
124     if (face_->size != ftSize && FT_Activate_Size(ftSize)) {
125         return FontDefs::ATLAS_ERROR;
126     }
127 
128     FT_Int32 flags = FT_LOAD_RENDER;
129 
130     if (sdf == true) {
131         flags |= FT_LOAD_TARGET_(FT_RENDER_MODE_SDF);
132     } else if (FT_HAS_COLOR(face_)) {
133         flags |= FT_LOAD_COLOR;
134     }
135 
136     if (FT_Load_Glyph(face_, glyphIndex, flags)) {
137         return FontDefs::ATLAS_ERROR;
138     }
139 
140     FT_Glyph bmp;
141     if (FT_Get_Glyph(face_->glyph, &bmp)) {
142         return FontDefs::ATLAS_ERROR;
143     }
144 
145     // sanity check
146     if (bmp->format != FT_GLYPH_FORMAT_BITMAP) {
147         FT_Done_Glyph(bmp);
148         return FontDefs::ATLAS_ERROR;
149     }
150 
151     FT_BBox bbox;
152     FT_Glyph_Get_CBox(bmp, FT_GLYPH_BBOX_UNSCALED, &bbox);
153 
154     glyph.xMin = FontDefs::FTPosToInt16(bbox.xMin);
155     glyph.xMax = FontDefs::FTPosToInt16(bbox.xMax);
156     glyph.yMin = FontDefs::FTPosToInt16(bbox.yMin);
157     glyph.yMax = FontDefs::FTPosToInt16(bbox.yMax);
158     glyph.hlsb = FontDefs::FTPosToInt16(face_->glyph->metrics.horiBearingX);
159     glyph.htsb = FontDefs::FTPosToInt16(face_->glyph->metrics.horiBearingY);
160     glyph.hAdv = FontDefs::FTPosToInt16(face_->glyph->metrics.horiAdvance);
161 
162     if (FT_HAS_VERTICAL(face_)) {
163         glyph.vlsb = FontDefs::FTPosToInt16(face_->glyph->metrics.vertBearingX);
164         glyph.vtsb = FontDefs::FTPosToInt16(face_->glyph->metrics.vertBearingY);
165         glyph.vAdv = FontDefs::FTPosToInt16(face_->glyph->metrics.vertAdvance);
166     }
167 
168     glyph.atlas.rect.w = 0;
169     bool isColor = false;
170     bool needsConversion = false;
171     switch (((FT_BitmapGlyph)bmp)->bitmap.pixel_mode) {
172         case FT_PIXEL_MODE_MONO:
173             needsConversion = true;
174             break;
175 
176         case FT_PIXEL_MODE_GRAY:
177             needsConversion = false;
178             break;
179 
180         case FT_PIXEL_MODE_GRAY2:
181             needsConversion = true;
182             break;
183 
184         case FT_PIXEL_MODE_GRAY4:
185             needsConversion = true;
186             break;
187 
188         case FT_PIXEL_MODE_BGRA:
189             needsConversion = false;
190             isColor = true;
191             break;
192 
193         case FT_PIXEL_MODE_NONE:
194         case FT_PIXEL_MODE_LCD:
195         case FT_PIXEL_MODE_LCD_V:
196         case FT_PIXEL_MODE_MAX:
197             CORE_LOG_E("unhandled pixel mode");
198             return FontDefs::ATLAS_ERROR;
199     }
200 
201     FT_Bitmap converted;
202     if (needsConversion) {
203         FT_Bitmap_Init(&converted);
204         FT_Bitmap_Convert(bmp->library, &((FT_BitmapGlyph)bmp)->bitmap, &converted, 1);
205 
206         if (converted.num_grays == 2U) { // 2 : param
207             // convert created a binary bitmap, expand to 0..255 range.
208             std::transform(converted.buffer, converted.buffer + converted.pitch * converted.rows, converted.buffer,
209                 [](const uint8_t& c) { return (c) ? uint8_t(0xffU) : uint8_t(0x00U); });
210         } else if (converted.num_grays == 4U) { // 4 ;param
211             // convert created a 2 bit bitmap, expand to 0..255 range.
212             std::transform(converted.buffer, converted.buffer + converted.pitch * converted.rows, converted.buffer,
213                 [](const uint8_t& c) {
214                     auto half = (c << 2U) | c; // 2 : param
215                     return uint8_t((half << 4U) | half); // 4 : param
216                 });
217         } else if (converted.num_grays == 16U) { // 16 : channel
218             // convert created a 4 bit bitmap, expand to 0..255 range.
219             std::transform(converted.buffer, converted.buffer + converted.pitch * converted.rows, converted.buffer,
220                 [](const uint8_t& c) { return uint8_t((c << 4U) | c); }); // 4 : param
221         }
222     }
223 
224     GetFontManager().UpdateAtlas(glyph, ((FT_BitmapGlyph)bmp)->bitmap, isColor);
225 
226     if (needsConversion) {
227         FT_Bitmap_Done(bmp->library, &converted);
228     }
229 
230     FT_Done_Glyph(bmp);
231     return 0;
232 }
233 
GetGlyphIndex(uint32_t utfCode)234 uint32_t FaceData::GetGlyphIndex(uint32_t utfCode)
235 {
236     std::shared_lock readerLock(mutex_);
237 
238     return FT_Get_Char_Index(face_, utfCode);
239 }
240 FONT_END_NAMESPACE()
241