• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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