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