• 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 "font_data.h"
17 
18 #include <freetype/ftsizes.h>
19 #include <freetype/ftstroke.h>
20 
21 #include <base/containers/fixed_string.h>
22 #include <base/containers/string.h>
23 #include <base/util/utf8_decode.h>
24 #include <render/resource_handle.h>
25 
26 #include "face_data.h"
27 #include "font.h"
28 #include "font_manager.h"
29 
30 using namespace BASE_NS;
31 using namespace RENDER_NS;
32 
33 namespace {
CalcKerning(FT_Face face,uint32_t prevGlyphIndex,uint32_t glyphIndex)34 FT_Pos CalcKerning(FT_Face face, uint32_t prevGlyphIndex, uint32_t glyphIndex)
35 {
36     FT_Vector delta;
37     FT_Get_Kerning(face, prevGlyphIndex, glyphIndex, FT_KERNING_UNFITTED, &delta);
38     return delta.x;
39 }
40 } // namespace
41 
FONT_BEGIN_NAMESPACE()42 FONT_BEGIN_NAMESPACE()
43 std::unique_ptr<FontData> FontData::CreateFromFaceData(const std::weak_ptr<FaceData>& face, bool sdf)
44 {
45     auto faceFromWeak = face.lock();
46     if (!faceFromWeak) {
47         return {};
48     }
49     FT_Size size {};
50     FT_Error err = FT_New_Size(faceFromWeak->face_, &size);
51     if (err) {
52         return {};
53     }
54     err = FT_Activate_Size(size);
55     return std::make_unique<FontData>(face, size, sdf);
56 }
57 
FontData(const std::weak_ptr<FaceData> & face,FT_Size size,bool sdf)58 FontData::FontData(const std::weak_ptr<FaceData>& face, FT_Size size, bool sdf)
59     : faceData_(face), sizeData_(size), sdfData_(sdf)
60 {}
61 
~FontData()62 FontData::~FontData()
63 {
64     FT_Done_Size(sizeData_);
65 }
66 
GetSize()67 FontSize FontData::GetSize()
68 {
69     return sizeData_->metrics.y_ppem;
70 }
71 
MeasureString(const string_view string)72 Math::Vec2 FontData::MeasureString(const string_view string)
73 {
74     auto faceData = faceData_.lock();
75     if (!faceData) {
76         return {};
77     }
78 
79     const char* str = string.data();
80     const char* strEnd = string.data() + string.length();
81 
82     uint32_t prevGlyphIndex = 0;
83     bool kerning = false; // FT_HAS_KERNING(face_);
84     int32_t penX = 0;
85     int16_t maxDescent = INT16_MAX;
86     int16_t maxAscent = INT16_MIN;
87 
88     for (uint32_t code = 0; (str < strEnd) && (code = GetCharUtf8(&str), code);) {
89         const uint32_t glyphIndex = FT_Get_Char_Index(faceData->face_, code);
90         const FontDefs::Glyph* glyph = GetOrCreateCachedGlyph(glyphIndex);
91         if (!glyph) {
92             continue;
93         }
94 
95         if (prevGlyphIndex && kerning) {
96             penX += CalcKerning(faceData->face_, prevGlyphIndex, glyphIndex);
97         }
98 
99         prevGlyphIndex = glyphIndex;
100 
101         penX += FontDefs::Int16ToFTPos(glyph->hAdv);
102         if (maxDescent > glyph->yMin) {
103             maxDescent = glyph->yMin;
104         }
105         if (maxAscent < glyph->yMax) {
106             maxAscent = glyph->yMax;
107         }
108     }
109     return { FontDefs::FTPosToFloat(penX), FontDefs::Int16ToFloat(maxAscent - maxDescent) };
110 }
111 
GetMetrics()112 FontMetrics FontData::GetMetrics()
113 {
114     FontMetrics fontMetrics {};
115     auto faceData = faceData_.lock();
116     if (!faceData) {
117         return {};
118     }
119 
120     if (faceData->face_->units_per_EM == 0) {
121         fontMetrics.ascent = -FontDefs::FTPosToFloat(sizeData_->metrics.ascender);
122         fontMetrics.descent = -FontDefs::FTPosToFloat(sizeData_->metrics.descender);
123         fontMetrics.height = FontDefs::FTPosToFloat(sizeData_->metrics.height);
124         fontMetrics.leading = FontDefs::FTPosToFloat(
125             sizeData_->metrics.height + (sizeData_->metrics.descender - sizeData_->metrics.ascender));
126     } else {
127         fontMetrics.ascent = static_cast<float>(-FontDefs::Fp26ToInt(sizeData_->metrics.ascender));
128         fontMetrics.descent = static_cast<float>(-FontDefs::Fp26ToInt(sizeData_->metrics.descender));
129         fontMetrics.height = static_cast<float>(FontDefs::Fp26ToInt(sizeData_->metrics.height));
130         fontMetrics.leading = static_cast<float>(FontDefs::Fp26ToInt(
131             sizeData_->metrics.height - sizeData_->metrics.ascender + sizeData_->metrics.descender));
132     }
133 
134     uint32_t xIndex = faceData->GetGlyphIndex('x');
135     if (xIndex) {
136         GlyphMetrics glyphMetrics = GetGlyphMetrics(xIndex);
137         fontMetrics.x_height = glyphMetrics.top - glyphMetrics.bottom; // verify this value
138     } else {
139         // double check what to do if 'x' char is not found in face
140         fontMetrics.x_height = -fontMetrics.ascent;
141     }
142 
143     return fontMetrics;
144 }
145 
GetGlyphMetrics(uint32_t glyphIndex)146 GlyphMetrics FontData::GetGlyphMetrics(uint32_t glyphIndex)
147 {
148     GlyphMetrics glyphMetrics = {};
149 
150     const FontDefs::Glyph* glyph = GetOrCreateCachedGlyph(glyphIndex);
151     if (glyph) {
152         glyphMetrics.left = FontDefs::Int16ToFloat(glyph->xMin);
153         glyphMetrics.top = FontDefs::Int16ToFloat(glyph->yMax);
154         glyphMetrics.right = FontDefs::Int16ToFloat(glyph->xMax);
155         glyphMetrics.bottom = FontDefs::Int16ToFloat(glyph->yMin);
156 
157         glyphMetrics.advance = FontDefs::Int16ToFloat(glyph->hAdv);
158         glyphMetrics.leftBearing = FontDefs::Int16ToFloat(glyph->hlsb);
159         glyphMetrics.topBearing = FontDefs::Int16ToFloat(glyph->htsb);
160     }
161     return glyphMetrics;
162 }
163 
GetGlyphContours(uint32_t glyphIndex)164 BASE_NS::vector<GlyphContour> FontData::GetGlyphContours(uint32_t glyphIndex)
165 {
166     BASE_NS::vector<GlyphContour> contours;
167 
168     const auto faceData = faceData_.lock();
169     if (!faceData || !faceData->face_) {
170         return contours;
171     }
172 
173     if (FT_Load_Glyph(faceData->face_, glyphIndex, FT_LOAD_DEFAULT) != 0) {
174         return contours;
175     }
176 
177     const FT_Outline* outline = &faceData->face_->glyph->outline;
178     if (outline->n_points <= 0) {
179         return contours;
180     }
181 
182     short contourStart = 0U;
183 
184     for (short ii = 0U; ii < outline->n_contours; ii++) {
185         const short contourEnd = outline->contours[ii];
186         GlyphContour contour;
187         contour.points.reserve(static_cast<size_t>(contourEnd - contourStart));
188 
189         for (short jj = contourStart; jj <= contourEnd; jj++) {
190             const FT_Vector& point = outline->points[jj];
191             contour.points.emplace_back(FontDefs::FTPosToFloat(point.x), FontDefs::FTPosToFloat(point.y));
192         }
193         contours.push_back(BASE_NS::move(contour));
194         contourStart = contourEnd + 1;
195     }
196 
197     return contours;
198 }
199 
GetGlyphInfo(uint32_t glyphIndex)200 GlyphInfo FontData::GetGlyphInfo(uint32_t glyphIndex)
201 {
202     GlyphInfo glyphInfo = {};
203 
204     const FontDefs::Glyph* glyph = GetOrCreateCachedGlyph(glyphIndex);
205     if (!glyph) {
206         return glyphInfo;
207     }
208     auto faceData = faceData_.lock();
209     if (!faceData) {
210         return glyphInfo;
211     }
212 
213     auto& fontMgr = faceData->GetFontManager();
214     if (auto atlas = fontMgr.GetAtlas(glyph->atlas.index); atlas) {
215         glyphInfo.atlas = atlas->handle;
216     }
217 
218     glyphInfo.tl.x = glyph->atlas.rect.x;
219     glyphInfo.tl.y = glyph->atlas.rect.y;
220     glyphInfo.br.x = glyphInfo.tl.x + glyph->atlas.rect.w;
221     glyphInfo.br.y = glyphInfo.tl.y + glyph->atlas.rect.h;
222     glyphInfo.tl /= FontDefs::ATLAS_SIZE;
223     glyphInfo.br /= FontDefs::ATLAS_SIZE;
224 
225     return glyphInfo;
226 }
227 
GetOrCreateCachedGlyph(uint32_t glyphIndex)228 const FontDefs::Glyph* FontData::GetOrCreateCachedGlyph(uint32_t glyphIndex)
229 {
230     std::shared_lock readerLock(mutex_);
231     auto glyphPos = glyphCache_.find(glyphIndex);
232     if (glyphPos != glyphCache_.end()) {
233         return &glyphPos->second;
234     }
235     readerLock.unlock();
236     return UpdateGlyph(glyphIndex);
237 }
238 
UpdateGlyph(uint32_t glyphIndex)239 const FontDefs::Glyph* FontData::UpdateGlyph(uint32_t glyphIndex)
240 {
241     std::lock_guard writerLock(mutex_);
242     if (auto glyphPos = glyphCache_.find(glyphIndex); glyphPos != glyphCache_.end()) {
243         return &glyphPos->second;
244     }
245     auto faceData = faceData_.lock();
246     if (!faceData) {
247         return {};
248     }
249 
250     FontDefs::Glyph& glyph = glyphCache_[glyphIndex];
251     if (faceData->UpdateGlyph(sdfData_, sizeData_, glyphIndex, glyph)) {
252         return nullptr;
253     }
254     return &glyph;
255 }
256 FONT_END_NAMESPACE()
257