xref: /aosp_15_r20/external/skia/tools/fonts/FontToolUtils.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2014 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "tools/fonts/FontToolUtils.h"
9 
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkFont.h"
13 #include "include/core/SkFontMgr.h"
14 #include "include/core/SkFontStyle.h"
15 #include "include/core/SkFontTypes.h"
16 #include "include/core/SkImage.h"
17 #include "include/core/SkPaint.h"
18 #include "include/core/SkPixelRef.h"  // IWYU pragma: keep
19 #include "include/core/SkStream.h"
20 #include "include/core/SkTypeface.h"
21 #include "include/private/base/SkMutex.h"
22 #include "include/utils/SkCustomTypeface.h"
23 #include "src/base/SkUTF.h"
24 #include "src/core/SkOSFile.h"
25 #include "tools/Resources.h"
26 #include "tools/flags/CommandLineFlags.h"
27 #include "tools/fonts/TestFontMgr.h"
28 
29 #if defined(SK_BUILD_FOR_WIN) && (defined(SK_FONTMGR_GDI_AVAILABLE) || \
30                                   defined(SK_FONTMGR_DIRECTWRITE_AVAILABLE))
31 #include "include/ports/SkTypeface_win.h"
32 #endif
33 
34 #if defined(SK_BUILD_FOR_ANDROID) && defined(SK_FONTMGR_ANDROID_AVAILABLE)
35 #include "include/ports/SkFontMgr_android.h"
36 #include "include/ports/SkFontScanner_FreeType.h"
37 #endif
38 
39 #if defined(SK_BUILD_FOR_ANDROID) && defined(SK_FONTMGR_ANDROID_NDK_AVAILABLE)
40 #include "include/ports/SkFontMgr_android_ndk.h"
41 #include "include/ports/SkFontScanner_FreeType.h"
42 #endif
43 
44 #if defined(SK_FONTMGR_CORETEXT_AVAILABLE) && (defined(SK_BUILD_FOR_IOS) || \
45                                                defined(SK_BUILD_FOR_MAC))
46 #include "include/ports/SkFontMgr_mac_ct.h"
47 #endif
48 
49 #if defined(SK_FONTMGR_FONTATIONS_AVAILABLE)
50 #include "include/ports/SkFontMgr_Fontations.h"
51 #endif
52 
53 #if defined(SK_BUILD_FOR_UNIX) && defined(SK_FONTMGR_FONTCONFIG_AVAILABLE)
54 #include "include/ports/SkFontMgr_fontconfig.h"
55 #include "include/ports/SkFontScanner_FreeType.h"
56 #endif
57 
58 #if defined(SK_FONTMGR_FREETYPE_DIRECTORY_AVAILABLE)
59 #include "include/ports/SkFontMgr_directory.h"
60 #endif
61 
62 #if defined(SK_FONTMGR_FREETYPE_EMPTY_AVAILABLE)
63 #include "include/ports/SkFontMgr_empty.h"
64 #endif
65 
66 namespace ToolUtils {
67 
68 static DEFINE_bool(nativeFonts,
69                    true,
70                    "If true, use native font manager and rendering. "
71                    "If false, fonts will draw as portably as possible.");
72 #if defined(SK_BUILD_FOR_WIN)
73 static DEFINE_bool(gdi, false, "Use GDI instead of DirectWrite for font rendering.");
74 #endif
75 #if defined(SK_FONTMGR_FONTATIONS_AVAILABLE)
76 static DEFINE_bool(fontations, false, "Use Fontations for native font rendering.");
77 #endif
78 #if defined(SK_FONTMGR_ANDROID_NDK_AVAILABLE)
79 static DEFINE_bool(androidndkfonts, false, "Use AndroidNDK for native font rendering.");
80 #endif
81 
PlanetTypeface()82 sk_sp<SkTypeface> PlanetTypeface() {
83     static const sk_sp<SkTypeface> planetTypeface = []() {
84         const char* filename;
85 #if defined(SK_BUILD_FOR_WIN)
86         filename = "fonts/planetcolr.ttf";
87 #elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
88         filename = "fonts/planetsbix.ttf";
89 #else
90         filename = "fonts/planetcbdt.ttf";
91 #endif
92         sk_sp<SkTypeface> typeface = CreateTypefaceFromResource(filename);
93         if (typeface) {
94             return typeface;
95         }
96         return CreateTestTypeface("Planet", SkFontStyle());
97     }();
98     return planetTypeface;
99 }
100 
EmojiSample()101 EmojiTestSample EmojiSample() {
102     static const EmojiTestSample emojiSample = []() {
103         EmojiTestSample sample = {nullptr, ""};
104 #if defined(SK_BUILD_FOR_WIN)
105         sample = EmojiSample(EmojiFontFormat::ColrV0);
106 #elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
107         sample = EmojiSample(EmojiFontFormat::Sbix);
108 #else
109         sample = EmojiSample(EmojiFontFormat::Cbdt);
110 #endif
111         if (sample.typeface) {
112             return sample;
113         }
114         return EmojiSample(EmojiFontFormat::Test);
115     }();
116     return emojiSample;
117 }
118 
EmojiSample(EmojiFontFormat format)119 EmojiTestSample EmojiSample(EmojiFontFormat format) {
120     EmojiTestSample sample;
121     sample.sampleText = "\U0001F600 \u2662";  // �� ♢
122     switch (format) {
123         case EmojiFontFormat::Cbdt:
124             sample.typeface = CreateTypefaceFromResource("fonts/cbdt.ttf");
125             break;
126         case EmojiFontFormat::Sbix:
127             sample.typeface = CreateTypefaceFromResource("fonts/sbix.ttf");
128             break;
129         case EmojiFontFormat::ColrV0:
130             sample.typeface = CreateTypefaceFromResource("fonts/colr.ttf");
131             break;
132         case EmojiFontFormat::Svg:
133             sample.typeface = CreateTypefaceFromResource("fonts/SampleSVG.ttf");
134             sample.sampleText = "abcdefghij";
135             break;
136         case EmojiFontFormat::Test:
137             sample.typeface = CreatePortableTypeface("Emoji", SkFontStyle());
138     }
139     return sample;
140 }
141 
NameForFontFormat(EmojiFontFormat format)142 SkString NameForFontFormat(EmojiFontFormat format) {
143     switch (format) {
144         case EmojiFontFormat::Cbdt:
145             return SkString("cbdt");
146         case EmojiFontFormat::Sbix:
147             return SkString("sbix");
148         case EmojiFontFormat::ColrV0:
149             return SkString("colrv0");
150         case EmojiFontFormat::Test:
151             return SkString("test");
152         case EmojiFontFormat::Svg:
153             return SkString("svg");
154     }
155     return SkString();
156 }
157 
SampleUserTypeface()158 sk_sp<SkTypeface> SampleUserTypeface() {
159     SkCustomTypefaceBuilder builder;
160     SkFont font;
161     const float upem = 200;
162 
163     {
164         SkFontMetrics metrics;
165         metrics.fFlags = 0;
166         metrics.fTop = -200;
167         metrics.fAscent = -150;
168         metrics.fDescent = 50;
169         metrics.fBottom = -75;
170         metrics.fLeading = 10;
171         metrics.fAvgCharWidth = 150;
172         metrics.fMaxCharWidth = 300;
173         metrics.fXMin = -20;
174         metrics.fXMax = 290;
175         metrics.fXHeight = -100;
176         metrics.fCapHeight = 0;
177         metrics.fUnderlineThickness = 5;
178         metrics.fUnderlinePosition = 2;
179         metrics.fStrikeoutThickness = 5;
180         metrics.fStrikeoutPosition = -50;
181         builder.setMetrics(metrics, 1.0f/upem);
182     }
183     builder.setFontStyle(SkFontStyle(367, 3, SkFontStyle::kOblique_Slant));
184 
185     const SkMatrix scale = SkMatrix::Scale(1.0f/upem, 1.0f/upem);
186     for (SkGlyphID index = 0; index <= 67; ++index) {
187         SkScalar width;
188         width = 100;
189 
190         builder.setGlyph(index, width/upem, SkPath::Circle(50, -50, 75).makeTransform(scale));
191     }
192 
193     return builder.detach();
194 }
195 
CreatePortableTypeface(const char * name,SkFontStyle style)196 sk_sp<SkTypeface> CreatePortableTypeface(const char* name, SkFontStyle style) {
197     static sk_sp<SkFontMgr> portableFontMgr = MakePortableFontMgr();
198     SkASSERT_RELEASE(portableFontMgr);
199     sk_sp<SkTypeface> face = portableFontMgr->legacyMakeTypeface(name, style);
200     SkASSERT_RELEASE(face);
201     return face;
202 }
203 
DefaultPortableTypeface()204 sk_sp<SkTypeface> DefaultPortableTypeface() {
205     // At last check, the default typeface is a serif font.
206     sk_sp<SkTypeface> face = CreatePortableTypeface(nullptr, SkFontStyle());
207     SkASSERT_RELEASE(face);
208     return face;
209 }
210 
DefaultPortableFont()211 SkFont DefaultPortableFont() {
212     return SkFont(DefaultPortableTypeface(), 12);
213 }
214 
CreateStringBitmap(int w,int h,SkColor c,int x,int y,int textSize,const char * str)215 SkBitmap CreateStringBitmap(int w, int h, SkColor c, int x, int y, int textSize,
216                             const char* str) {
217     SkBitmap bitmap;
218     bitmap.allocN32Pixels(w, h);
219     SkCanvas canvas(bitmap);
220 
221     SkPaint paint;
222     paint.setColor(c);
223 
224     SkFont font(DefaultPortableTypeface(), textSize);
225 
226     canvas.clear(0x00000000);
227     canvas.drawSimpleText(str,
228                           strlen(str),
229                           SkTextEncoding::kUTF8,
230                           SkIntToScalar(x),
231                           SkIntToScalar(y),
232                           font,
233                           paint);
234 
235     // Tag data as sRGB (without doing any color space conversion). Color-space aware configs
236     // will process this correctly but legacy configs will render as if this returned N32.
237     SkBitmap result;
238     result.setInfo(SkImageInfo::MakeS32(w, h, kPremul_SkAlphaType));
239     result.setPixelRef(sk_ref_sp(bitmap.pixelRef()), 0, 0);
240     return result;
241 }
242 
CreateStringImage(int w,int h,SkColor c,int x,int y,int textSize,const char * str)243 sk_sp<SkImage> CreateStringImage(int w, int h, SkColor c, int x, int y, int textSize,
244                                  const char* str) {
245     return CreateStringBitmap(w, h, c, x, y, textSize, str).asImage();
246 }
247 
248 #ifndef SK_FONT_FILE_PREFIX
249 #  if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
250 #    define SK_FONT_FILE_PREFIX "/System/Library/Fonts/"
251 #  else
252 #    define SK_FONT_FILE_PREFIX "/usr/share/fonts/"
253 #  endif
254 #endif
255 
TestFontMgr()256 sk_sp<SkFontMgr> TestFontMgr() {
257     static sk_sp<SkFontMgr> mgr;
258     static SkOnce once;
259     once([] {
260         if (!FLAGS_nativeFonts) {
261             mgr = MakePortableFontMgr();
262         }
263 #if defined(SK_BUILD_FOR_WIN) && defined(SK_FONTMGR_GDI_AVAILABLE)
264         else if (FLAGS_gdi) {
265             mgr = SkFontMgr_New_GDI();
266         }
267 #endif
268 #if defined(SK_FONTMGR_FONTATIONS_AVAILABLE)
269         else if (FLAGS_fontations) {
270             mgr = SkFontMgr_New_Fontations_Empty();
271         }
272 #endif
273 #if defined(SK_BUILD_FOR_ANDROID) && defined(SK_FONTMGR_ANDROID_NDK_AVAILABLE) && defined(SK_TYPEFACE_FACTORY_FREETYPE)
274         else if (FLAGS_androidndkfonts) {
275             mgr = SkFontMgr_New_AndroidNDK(false, SkFontScanner_Make_FreeType());
276         }
277 #endif
278         else {
279 #if defined(SK_BUILD_FOR_ANDROID) && defined(SK_FONTMGR_ANDROID_AVAILABLE) && defined(SK_TYPEFACE_FACTORY_FREETYPE)
280             mgr = SkFontMgr_New_Android(nullptr, SkFontScanner_Make_FreeType());
281 #elif defined(SK_BUILD_FOR_WIN) && defined(SK_FONTMGR_DIRECTWRITE_AVAILABLE)
282             mgr = SkFontMgr_New_DirectWrite();
283 #elif defined(SK_FONTMGR_CORETEXT_AVAILABLE) && (defined(SK_BUILD_FOR_IOS) || \
284                                                 defined(SK_BUILD_FOR_MAC))
285             mgr = SkFontMgr_New_CoreText(nullptr);
286 #elif defined(SK_FONTMGR_FONTCONFIG_AVAILABLE) && defined(SK_TYPEFACE_FACTORY_FREETYPE)
287             mgr = SkFontMgr_New_FontConfig(nullptr, SkFontScanner_Make_FreeType());
288 #elif defined(SK_FONTMGR_FREETYPE_DIRECTORY_AVAILABLE)
289             // In particular, this is used on ChromeOS, which is Linux-like but doesn't have
290             // FontConfig.
291             mgr = SkFontMgr_New_Custom_Directory(SK_FONT_FILE_PREFIX);
292 #elif defined(SK_FONTMGR_FREETYPE_EMPTY_AVAILABLE)
293             mgr = SkFontMgr_New_Custom_Empty();
294 #else
295             mgr = SkFontMgr::RefEmpty();
296 #endif
297         }
298         SkASSERT_RELEASE(mgr);
299     });
300     return mgr;
301 }
302 
FontMgrIsGDI()303 bool FontMgrIsGDI() {
304     if (!FLAGS_nativeFonts) {
305         return false;
306     }
307 #if defined(SK_BUILD_FOR_WIN)
308     if (FLAGS_gdi) {
309         return true;
310     }
311 #endif
312     return false;
313 }
314 
UsePortableFontMgr()315 void UsePortableFontMgr() { FLAGS_nativeFonts = false; }
316 
DefaultTypeface()317 sk_sp<SkTypeface> DefaultTypeface() {
318     return CreateTestTypeface(nullptr, SkFontStyle());
319 }
320 
CreateTestTypeface(const char * name,SkFontStyle style)321 sk_sp<SkTypeface> CreateTestTypeface(const char* name, SkFontStyle style) {
322     sk_sp<SkFontMgr> fm = TestFontMgr();
323     SkASSERT_RELEASE(fm);
324     sk_sp<SkTypeface> face = fm->legacyMakeTypeface(name, style);
325     if (face) {
326         return face;
327     }
328     return CreatePortableTypeface(name, style);
329 }
330 
CreateTypefaceFromResource(const char * resource,int ttcIndex)331 sk_sp<SkTypeface> CreateTypefaceFromResource(const char* resource, int ttcIndex) {
332     sk_sp<SkFontMgr> fm = TestFontMgr();
333     SkASSERT_RELEASE(fm);
334     return fm->makeFromStream(GetResourceAsStream(resource), ttcIndex);
335 }
336 
DefaultFont()337 SkFont DefaultFont() {
338     return SkFont(DefaultTypeface(), 12);
339 }
340 
341 }  // namespace ToolUtils
342