1 /*
2 * Copyright (c) 2023-2025 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 "text/font.h"
17
18 #include "modules/skunicode/include/SkUnicode.h"
19
20 #include "impl_factory.h"
21 #include "impl_interface/font_impl.h"
22 #include "text/font_mgr.h"
23 #include "utils/log.h"
24 #include "font_harfbuzz.h"
25
26
27 namespace OHOS {
28 namespace Rosen {
29 namespace Drawing {
30 constexpr const char* LANGUAGE_HAN = "zh-Hans";
31 constexpr size_t COUNT_REQUESTED = 32;
32 #ifdef USE_M133_SKIA
33 using SkFeaturesArray = skia_private::STArray<COUNT_REQUESTED, hb_feature_t>;
34 #else
35 using SkFeaturesArray = SkSTArray<COUNT_REQUESTED, hb_feature_t>;
36 #endif
37
Font()38 Font::Font() : fontImpl_(ImplFactory::CreateFontImpl()) {}
39
Font(std::shared_ptr<Typeface> typeface,scalar size,scalar scaleX,scalar skewX)40 Font::Font(std::shared_ptr<Typeface> typeface, scalar size, scalar scaleX, scalar skewX)
41 : fontImpl_(ImplFactory::CreateFontImpl(typeface, size, scaleX, skewX)) {}
42
Font(const Font & font)43 Font::Font(const Font& font) : fontImpl_(ImplFactory::CreateFontImpl(font)) {}
44
SetEdging(FontEdging edging)45 void Font::SetEdging(FontEdging edging)
46 {
47 fontImpl_->SetEdging(edging);
48 }
49
SetBaselineSnap(bool baselineSnap)50 void Font::SetBaselineSnap(bool baselineSnap)
51 {
52 fontImpl_->SetBaselineSnap(baselineSnap);
53 }
54
SetForceAutoHinting(bool isForceAutoHinting)55 void Font::SetForceAutoHinting(bool isForceAutoHinting)
56 {
57 fontImpl_->SetForceAutoHinting(isForceAutoHinting);
58 }
59
SetSubpixel(bool isSubpixel)60 void Font::SetSubpixel(bool isSubpixel)
61 {
62 fontImpl_->SetSubpixel(isSubpixel);
63 }
64
SetHinting(FontHinting hintingLevel)65 void Font::SetHinting(FontHinting hintingLevel)
66 {
67 fontImpl_->SetHinting(hintingLevel);
68 }
69
SetEmbeddedBitmaps(bool embeddedBitmaps)70 void Font::SetEmbeddedBitmaps(bool embeddedBitmaps)
71 {
72 fontImpl_->SetEmbeddedBitmaps(embeddedBitmaps);
73 }
74
SetTypeface(std::shared_ptr<Typeface> typeface)75 void Font::SetTypeface(std::shared_ptr<Typeface> typeface)
76 {
77 fontImpl_->SetTypeface(typeface);
78 }
79
SetSize(scalar textSize)80 void Font::SetSize(scalar textSize)
81 {
82 fontImpl_->SetSize(textSize);
83 }
84
SetEmbolden(bool isEmbolden)85 void Font::SetEmbolden(bool isEmbolden)
86 {
87 fontImpl_->SetEmbolden(isEmbolden);
88 }
89
SetScaleX(scalar scaleX)90 void Font::SetScaleX(scalar scaleX)
91 {
92 fontImpl_->SetScaleX(scaleX);
93 }
94
SetSkewX(scalar skewX)95 void Font::SetSkewX(scalar skewX)
96 {
97 fontImpl_->SetSkewX(skewX);
98 }
99
SetLinearMetrics(bool isLinearMetrics)100 void Font::SetLinearMetrics(bool isLinearMetrics)
101 {
102 fontImpl_->SetLinearMetrics(isLinearMetrics);
103 }
104
GetMetrics(FontMetrics * metrics) const105 scalar Font::GetMetrics(FontMetrics* metrics) const
106 {
107 return fontImpl_->GetMetrics(metrics);
108 }
109
GetWidths(const uint16_t glyphs[],int count,scalar widths[]) const110 void Font::GetWidths(const uint16_t glyphs[], int count, scalar widths[]) const
111 {
112 fontImpl_->GetWidths(glyphs, count, widths);
113 }
114
GetWidths(const uint16_t glyphs[],int count,scalar widths[],Rect bounds[]) const115 void Font::GetWidths(const uint16_t glyphs[], int count, scalar widths[], Rect bounds[]) const
116 {
117 fontImpl_->GetWidths(glyphs, count, widths, bounds);
118 }
119
GetSize() const120 scalar Font::GetSize() const
121 {
122 return fontImpl_->GetSize();
123 }
124
GetTypeface() const125 std::shared_ptr<Typeface> Font::GetTypeface() const
126 {
127 return fontImpl_->GetTypeface();
128 }
129
GetEdging() const130 FontEdging Font::GetEdging() const
131 {
132 return fontImpl_->GetEdging();
133 }
134
GetHinting() const135 FontHinting Font::GetHinting() const
136 {
137 return fontImpl_->GetHinting();
138 }
139
IsEmbeddedBitmaps() const140 bool Font::IsEmbeddedBitmaps() const
141 {
142 return fontImpl_->IsEmbeddedBitmaps();
143 }
144
GetScaleX() const145 scalar Font::GetScaleX() const
146 {
147 return fontImpl_->GetScaleX();
148 }
149
GetSkewX() const150 scalar Font::GetSkewX() const
151 {
152 return fontImpl_->GetSkewX();
153 }
154
IsBaselineSnap() const155 bool Font::IsBaselineSnap() const
156 {
157 return fontImpl_->IsBaselineSnap();
158 }
159
IsForceAutoHinting() const160 bool Font::IsForceAutoHinting() const
161 {
162 return fontImpl_->IsForceAutoHinting();
163 }
164
IsSubpixel() const165 bool Font::IsSubpixel() const
166 {
167 return fontImpl_->IsSubpixel();
168 }
169
IsLinearMetrics() const170 bool Font::IsLinearMetrics() const
171 {
172 return fontImpl_->IsLinearMetrics();
173 }
174
IsEmbolden() const175 bool Font::IsEmbolden() const
176 {
177 return fontImpl_->IsEmbolden();
178 }
179
UnicharToGlyph(int32_t uni) const180 uint16_t Font::UnicharToGlyph(int32_t uni) const
181 {
182 return fontImpl_->UnicharToGlyph(uni);
183 }
184
ValidateAndCopyFontFeaturesToHbFeatures(const Drawing::DrawingFontFeatures & fontFeatures,SkFeaturesArray & hbFeatures)185 void ValidateAndCopyFontFeaturesToHbFeatures(const Drawing::DrawingFontFeatures& fontFeatures,
186 SkFeaturesArray& hbFeatures)
187 {
188 for (const auto& featureMap : fontFeatures) {
189 for (const auto& [key, value] : featureMap) {
190 if (key.size() != 4) { // 4 OpenType font feature name is fixed to be 4 chars.
191 LOGW("Invalid feature name. font feature name has to be 4 chars");
192 continue;
193 }
194 SkFourByteTag tag = SkSetFourByteTag(key[0], key[1], key[2], key[3]);
195 hbFeatures.push_back({(hb_tag_t)tag, (uint32_t)value, HB_FEATURE_GLOBAL_START, HB_FEATURE_GLOBAL_END});
196 }
197 }
198 }
199
UnicharToGlyphWithFeatures(const char * uni,std::shared_ptr<Drawing::DrawingFontFeatures> fontFeatures) const200 uint16_t Font::UnicharToGlyphWithFeatures(const char* uni,
201 std::shared_ptr<Drawing::DrawingFontFeatures> fontFeatures) const
202 {
203 if (fontFeatures == nullptr) {
204 LOGE("font features is null, return glyphId as 0");
205 return 0;
206 }
207
208 const size_t utf8Bytes = strlen(uni);
209 const char* utf8Start = uni;
210 const char* utf8End = utf8Start + utf8Bytes;
211
212 FontHarfbuzz::HBBuffer buffer(hb_buffer_create());
213 hb_buffer_t *buffer1 = buffer.get();
214 SkAutoTCallVProc<hb_buffer_t, hb_buffer_clear_contents> autoClearBuffer(buffer1);
215 hb_buffer_set_content_type(buffer1, HB_BUFFER_CONTENT_TYPE_UNICODE);
216 hb_buffer_set_cluster_level(buffer1, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
217 hb_buffer_add_utf8(buffer1, uni, 0, utf8Bytes, 0);
218
219 const char* utf8Current = utf8Start;
220 while (utf8Current < utf8End) {
221 uint32_t cluster = utf8Current - uni;
222 SkUnichar val = SkUTF::NextUTF8(&utf8Current, utf8End);
223 hb_codepoint_t u = val < 0 ? 0XFFDD : static_cast<hb_codepoint_t>(val);
224 hb_buffer_add(buffer1, u, cluster);
225 }
226
227 const hb_language_t language = hb_language_from_string(LANGUAGE_HAN, -1);
228 hb_buffer_set_language(buffer1, language);
229 hb_buffer_guess_segment_properties(buffer1);
230
231 FontHarfbuzz::HBFont hbFont;
232 {
233 std::shared_ptr<Typeface> typeface = GetTypeface();
234 if (!typeface) {
235 LOGW("typeface is null, return glyphId as 0");
236 return 0;
237 }
238 FontHarfbuzz::HBFont typefaceFont(FontHarfbuzz::CreateTypefaceHbFont(*typeface));
239 hbFont = FontHarfbuzz::CreateSubHbFont(*this, typefaceFont);
240 }
241
242 SkFeaturesArray hbFeatures;
243 ValidateAndCopyFontFeaturesToHbFeatures(*fontFeatures, hbFeatures);
244 hb_shape(hbFont.get(), buffer1, hbFeatures.data(), hbFeatures.size());
245 if (hb_buffer_get_length(buffer1) == 0) {
246 LOGW("buffer is empty, return glyphId as 0");
247 return 0;
248 }
249
250 hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer1, nullptr);
251 if (info == nullptr) {
252 LOGW("glyph info generate failed, return glyphId as 0");
253 return 0;
254 }
255 return info[0].codepoint;
256 }
257
TextToGlyphs(const void * text,size_t byteLength,TextEncoding encoding,uint16_t glyphs[],int maxGlyphCount) const258 int Font::TextToGlyphs(const void* text, size_t byteLength, TextEncoding encoding,
259 uint16_t glyphs[], int maxGlyphCount) const
260 {
261 return fontImpl_->TextToGlyphs(text, byteLength, encoding, glyphs, maxGlyphCount);
262 }
263
MeasureText(const void * text,size_t byteLength,TextEncoding encoding,Rect * bounds) const264 scalar Font::MeasureText(const void* text, size_t byteLength, TextEncoding encoding, Rect* bounds) const
265 {
266 return fontImpl_->MeasureText(text, byteLength, encoding, bounds);
267 }
268
MeasureText(const void * text,size_t byteLength,TextEncoding encoding,Rect * bounds,const Brush * brush,const Pen * pen) const269 scalar Font::MeasureText(const void* text, size_t byteLength, TextEncoding encoding, Rect* bounds, const Brush* brush,
270 const Pen* pen) const
271 {
272 if (brush != nullptr && pen != nullptr) {
273 LOGE("Font::MeasureText brush and pen are both not nullptr");
274 return 0.0f;
275 }
276 return fontImpl_->MeasureText(text, byteLength, encoding, bounds, brush, pen);
277 }
278
GetWidthsBounds(const uint16_t glyphs[],int count,float widths[],Rect bounds[],const Brush * brush,const Pen * pen) const279 void Font::GetWidthsBounds(
280 const uint16_t glyphs[], int count, float widths[], Rect bounds[], const Brush* brush, const Pen* pen) const
281 {
282 if (brush != nullptr && pen != nullptr) {
283 LOGE("Font::GetWidthsBounds brush and pen are both not nullptr");
284 return;
285 }
286 fontImpl_->GetWidthsBounds(glyphs, count, widths, bounds, brush, pen);
287 }
288
GetPos(const uint16_t glyphs[],int count,Point points[],Point origin) const289 void Font::GetPos(const uint16_t glyphs[], int count, Point points[], Point origin) const
290 {
291 fontImpl_->GetPos(glyphs, count, points, origin);
292 }
293
GetSpacing() const294 float Font::GetSpacing() const
295 {
296 return fontImpl_->GetSpacing();
297 }
298
MeasureSingleCharacter(int32_t unicode) const299 scalar Font::MeasureSingleCharacter(int32_t unicode) const
300 {
301 scalar textWidth = 0.0f;
302 uint16_t glyph = UnicharToGlyph(unicode);
303 if (glyph != 0) {
304 textWidth = MeasureText(&glyph, sizeof(uint16_t), TextEncoding::GLYPH_ID);
305 } else {
306 std::shared_ptr<Font> fallbackFont = GetFallbackFont(unicode);
307 if (fallbackFont) {
308 uint16_t fallbackGlyph = fallbackFont->UnicharToGlyph(unicode);
309 textWidth = fallbackFont->MeasureText(&fallbackGlyph, sizeof(uint16_t), TextEncoding::GLYPH_ID);
310 }
311 }
312 return textWidth;
313 }
314
MeasureSingleCharacterWithFeatures(const char * unicode,int32_t unicodeId,std::shared_ptr<Drawing::DrawingFontFeatures> fontFeatures) const315 scalar Font::MeasureSingleCharacterWithFeatures(const char* unicode, int32_t unicodeId,
316 std::shared_ptr<Drawing::DrawingFontFeatures> fontFeatures) const
317 {
318 scalar textWidth = 0.0f;
319 uint16_t glyph = UnicharToGlyphWithFeatures(unicode, fontFeatures);
320 if (glyph != 0) {
321 textWidth = MeasureText(&glyph, sizeof(uint16_t), TextEncoding::GLYPH_ID);
322 } else {
323 std::shared_ptr<Font> fallbackFont = GetFallbackFont(unicodeId);
324 if (fallbackFont) {
325 uint16_t fallbackGlyph = fallbackFont->UnicharToGlyphWithFeatures(unicode, fontFeatures);
326 textWidth = fallbackFont->MeasureText(&fallbackGlyph, sizeof(uint16_t), TextEncoding::GLYPH_ID);
327 }
328 }
329 return textWidth;
330 }
331
GetFallbackFont(int32_t unicode) const332 std::shared_ptr<Font> Font::GetFallbackFont(int32_t unicode) const
333 {
334 std::shared_ptr<FontMgr> fontMgr = FontMgr::CreateDefaultFontMgr();
335 if (fontMgr == nullptr) {
336 LOGE("Font::GetFallbackFont, default fontMgr is nullptr.");
337 return nullptr;
338 }
339 std::shared_ptr<Typeface> currentTypeface = GetTypeface();
340 std::shared_ptr<Typeface> fallbackTypeface = nullptr;
341 if (currentTypeface) {
342 fallbackTypeface = std::shared_ptr<Typeface>(fontMgr->MatchFamilyStyleCharacter(nullptr,
343 currentTypeface->GetFontStyle(), nullptr, 0, unicode < 0 ? 0xFFFD : unicode));
344 } else {
345 std::shared_ptr<Typeface> defaultTypeface = Typeface::MakeDefault();
346 fallbackTypeface = std::shared_ptr<Typeface>(fontMgr->MatchFamilyStyleCharacter(nullptr, defaultTypeface
347 ? defaultTypeface->GetFontStyle() : FontStyle(), nullptr, 0, unicode < 0 ? 0xFFFD : unicode));
348 }
349 if (fallbackTypeface == nullptr) {
350 LOGE("Font::GetFallbackFont, fallback typeface is nullptr.");
351 return nullptr;
352 }
353 std::shared_ptr<Font> fallbackFont = std::make_shared<Font>(*this);
354 fallbackFont->SetTypeface(fallbackTypeface);
355 return fallbackFont;
356 }
357
CountText(const void * text,size_t byteLength,TextEncoding encoding) const358 int Font::CountText(const void* text, size_t byteLength, TextEncoding encoding) const
359 {
360 return fontImpl_->CountText(text, byteLength, encoding);
361 }
362
GetPathForGlyph(uint16_t glyph,Path * path) const363 bool Font::GetPathForGlyph(uint16_t glyph, Path* path) const
364 {
365 return fontImpl_->GetPathForGlyph(glyph, path);
366 }
367
GetTextPath(const void * text,size_t byteLength,TextEncoding encoding,float x,float y,Path * path) const368 void Font::GetTextPath(const void* text, size_t byteLength, TextEncoding encoding, float x, float y, Path* path) const
369 {
370 fontImpl_->GetTextPath(text, byteLength, encoding, x, y, path);
371 }
372
SetThemeFontFollowed(bool followed)373 void Font::SetThemeFontFollowed(bool followed)
374 {
375 themeFontFollowed_ = followed;
376 }
377
IsThemeFontFollowed() const378 bool Font::IsThemeFontFollowed() const
379 {
380 return themeFontFollowed_;
381 }
382 } // namespace Drawing
383 } // namespace Rosen
384 } // namespace OHOS
385