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