Coverage Report

Created: 2024-05-20 07:14

/src/skia/tools/fonts/FontToolUtils.cpp
Line
Count
Source (jump to first uncovered line)
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
73
0
sk_sp<SkTypeface> PlanetTypeface() {
74
0
    static const sk_sp<SkTypeface> planetTypeface = []() {
75
0
        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
0
        filename = "fonts/planetcbdt.ttf";
82
0
#endif
83
0
        sk_sp<SkTypeface> typeface = CreateTypefaceFromResource(filename);
84
0
        if (typeface) {
85
0
            return typeface;
86
0
        }
87
0
        return CreateTestTypeface("Planet", SkFontStyle());
88
0
    }();
89
0
    return planetTypeface;
90
0
}
91
92
0
EmojiTestSample EmojiSample() {
93
0
    static const EmojiTestSample emojiSample = []() {
94
0
        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
0
        sample = EmojiSample(EmojiFontFormat::Cbdt);
101
0
#endif
102
0
        if (sample.typeface) {
103
0
            return sample;
104
0
        }
105
0
        return EmojiSample(EmojiFontFormat::Test);
106
0
    }();
107
0
    return emojiSample;
108
0
}
109
110
0
EmojiTestSample EmojiSample(EmojiFontFormat format) {
111
0
    EmojiTestSample sample;
112
0
    sample.sampleText = "\U0001F600 \u2662";  // 😀 ♢
113
0
    switch (format) {
114
0
        case EmojiFontFormat::Cbdt:
115
0
            sample.typeface = CreateTypefaceFromResource("fonts/cbdt.ttf");
116
0
            break;
117
0
        case EmojiFontFormat::Sbix:
118
0
            sample.typeface = CreateTypefaceFromResource("fonts/sbix.ttf");
119
0
            break;
120
0
        case EmojiFontFormat::ColrV0:
121
0
            sample.typeface = CreateTypefaceFromResource("fonts/colr.ttf");
122
0
            break;
123
0
        case EmojiFontFormat::Svg:
124
0
            sample.typeface = CreateTypefaceFromResource("fonts/SampleSVG.ttf");
125
0
            sample.sampleText = "abcdefghij";
126
0
            break;
127
0
        case EmojiFontFormat::Test:
128
0
            sample.typeface = CreatePortableTypeface("Emoji", SkFontStyle());
129
0
    }
130
0
    return sample;
131
0
}
132
133
0
SkString NameForFontFormat(EmojiFontFormat format) {
134
0
    switch (format) {
135
0
        case EmojiFontFormat::Cbdt:
136
0
            return SkString("cbdt");
137
0
        case EmojiFontFormat::Sbix:
138
0
            return SkString("sbix");
139
0
        case EmojiFontFormat::ColrV0:
140
0
            return SkString("colrv0");
141
0
        case EmojiFontFormat::Test:
142
0
            return SkString("test");
143
0
        case EmojiFontFormat::Svg:
144
0
            return SkString("svg");
145
0
    }
146
0
    return SkString();
147
0
}
148
149
0
sk_sp<SkTypeface> SampleUserTypeface() {
150
0
    SkCustomTypefaceBuilder builder;
151
0
    SkFont font;
152
0
    const float upem = 200;
153
154
0
    {
155
0
        SkFontMetrics metrics;
156
0
        metrics.fFlags = 0;
157
0
        metrics.fTop = -200;
158
0
        metrics.fAscent = -150;
159
0
        metrics.fDescent = 50;
160
0
        metrics.fBottom = -75;
161
0
        metrics.fLeading = 10;
162
0
        metrics.fAvgCharWidth = 150;
163
0
        metrics.fMaxCharWidth = 300;
164
0
        metrics.fXMin = -20;
165
0
        metrics.fXMax = 290;
166
0
        metrics.fXHeight = -100;
167
0
        metrics.fCapHeight = 0;
168
0
        metrics.fUnderlineThickness = 5;
169
0
        metrics.fUnderlinePosition = 2;
170
0
        metrics.fStrikeoutThickness = 5;
171
0
        metrics.fStrikeoutPosition = -50;
172
0
        builder.setMetrics(metrics, 1.0f/upem);
173
0
    }
174
0
    builder.setFontStyle(SkFontStyle(367, 3, SkFontStyle::kOblique_Slant));
175
176
0
    const SkMatrix scale = SkMatrix::Scale(1.0f/upem, 1.0f/upem);
177
0
    for (SkGlyphID index = 0; index <= 67; ++index) {
178
0
        SkScalar width;
179
0
        width = 100;
180
181
0
        builder.setGlyph(index, width/upem, SkPath::Circle(50, -50, 75).makeTransform(scale));
182
0
    }
183
184
0
    return builder.detach();
185
0
}
186
187
2.09k
sk_sp<SkTypeface> CreatePortableTypeface(const char* name, SkFontStyle style) {
188
2.09k
    static sk_sp<SkFontMgr> portableFontMgr = MakePortableFontMgr();
189
2.09k
    SkASSERT_RELEASE(portableFontMgr);
190
2.09k
    sk_sp<SkTypeface> face = portableFontMgr->legacyMakeTypeface(name, style);
191
2.09k
    SkASSERT_RELEASE(face);
192
2.09k
    return face;
193
2.09k
}
194
195
2.09k
sk_sp<SkTypeface> DefaultPortableTypeface() {
196
    // At last check, the default typeface is a serif font.
197
2.09k
    sk_sp<SkTypeface> face = CreatePortableTypeface(nullptr, SkFontStyle());
198
2.09k
    SkASSERT_RELEASE(face);
199
2.09k
    return face;
200
2.09k
}
201
202
0
SkFont DefaultPortableFont() {
203
0
    return SkFont(DefaultPortableTypeface(), 12);
204
0
}
205
206
SkBitmap CreateStringBitmap(int w, int h, SkColor c, int x, int y, int textSize,
207
0
                            const char* str) {
208
0
    SkBitmap bitmap;
209
0
    bitmap.allocN32Pixels(w, h);
210
0
    SkCanvas canvas(bitmap);
211
212
0
    SkPaint paint;
213
0
    paint.setColor(c);
214
215
0
    SkFont font(DefaultPortableTypeface(), textSize);
216
217
0
    canvas.clear(0x00000000);
218
0
    canvas.drawSimpleText(str,
219
0
                          strlen(str),
220
0
                          SkTextEncoding::kUTF8,
221
0
                          SkIntToScalar(x),
222
0
                          SkIntToScalar(y),
223
0
                          font,
224
0
                          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
0
    SkBitmap result;
229
0
    result.setInfo(SkImageInfo::MakeS32(w, h, kPremul_SkAlphaType));
230
0
    result.setPixelRef(sk_ref_sp(bitmap.pixelRef()), 0, 0);
231
0
    return result;
232
0
}
233
234
sk_sp<SkImage> CreateStringImage(int w, int h, SkColor c, int x, int y, int textSize,
235
0
                                 const char* str) {
236
0
    return CreateStringBitmap(w, h, c, x, y, textSize, str).asImage();
237
0
}
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
247
359k
sk_sp<SkFontMgr> TestFontMgr() {
248
359k
    static sk_sp<SkFontMgr> mgr;
249
359k
    static SkOnce once;
250
359k
    once([] {
251
5
        if (!FLAGS_nativeFonts) {
252
4
            mgr = MakePortableFontMgr();
253
4
        }
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
1
        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
1
        }
284
5
        SkASSERT_RELEASE(mgr);
285
5
    });
286
359k
    return mgr;
287
359k
}
288
289
0
bool FontMgrIsGDI() {
290
0
    if (!FLAGS_nativeFonts) {
291
0
        return false;
292
0
    }
293
#if defined(SK_BUILD_FOR_WIN)
294
    if (FLAGS_gdi) {
295
        return true;
296
    }
297
#endif
298
0
    return false;
299
0
}
300
301
87.3k
void UsePortableFontMgr() { FLAGS_nativeFonts = false; }
302
303
346k
sk_sp<SkTypeface> DefaultTypeface() {
304
346k
    return CreateTestTypeface(nullptr, SkFontStyle());
305
346k
}
306
307
346k
sk_sp<SkTypeface> CreateTestTypeface(const char* name, SkFontStyle style) {
308
346k
    sk_sp<SkFontMgr> fm = TestFontMgr();
309
346k
    SkASSERT_RELEASE(fm);
310
346k
    sk_sp<SkTypeface> face = fm->legacyMakeTypeface(name, style);
311
346k
    if (face) {
312
346k
        return face;
313
346k
    }
314
0
    return CreatePortableTypeface(name, style);
315
346k
}
316
317
0
sk_sp<SkTypeface> CreateTypefaceFromResource(const char* resource, int ttcIndex) {
318
0
    sk_sp<SkFontMgr> fm = TestFontMgr();
319
0
    SkASSERT_RELEASE(fm);
320
0
    return fm->makeFromStream(GetResourceAsStream(resource), ttcIndex);
321
0
}
322
323
346k
SkFont DefaultFont() {
324
346k
    return SkFont(DefaultTypeface(), 12);
325
346k
}
326
327
}  // namespace ToolUtils