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