• 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/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