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