blob: b3ee3b6b6b08e37972c19940003ab8942f0a8f8d [file] [log] [blame]
djsollen@google.com1f584ed2013-09-19 12:08:40 +00001/*
2 * Copyright 2013 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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkData.h"
9#include "include/core/SkFontMgr.h"
10#include "include/core/SkRefCnt.h"
11#include "include/core/SkStream.h"
12#include "include/core/SkTypeface.h"
Ben Wagnera541db4d2019-05-22 17:33:07 -040013#include "include/ports/SkTypeface_win.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "include/private/SkFixed.h"
15#include "src/core/SkAdvancedTypefaceMetrics.h"
16#include "src/core/SkFontDescriptor.h"
Ben Wagnera541db4d2019-05-22 17:33:07 -040017#include "src/core/SkFontMgrPriv.h"
18#include "src/core/SkFontPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "src/core/SkTypefaceCache.h"
20#include "src/sfnt/SkOTTable_OS_2.h"
21#include "src/sfnt/SkSFNTHeader.h"
Ben Wagnera541db4d2019-05-22 17:33:07 -040022#include "src/utils/SkUTF.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "tests/Test.h"
24#include "tools/Resources.h"
Ben Wagnera541db4d2019-05-22 17:33:07 -040025#include "tools/ToolUtils.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050026#include "tools/fonts/TestEmptyTypeface.h"
djsollen@google.com1f584ed2013-09-19 12:08:40 +000027
bungeman6e45bda2016-07-25 15:11:49 -070028#include <memory>
29
30static void TypefaceStyle_test(skiatest::Reporter* reporter,
31 uint16_t weight, uint16_t width, SkData* data)
32{
33 sk_sp<SkData> dataCopy;
reed42943c82016-09-12 12:01:44 -070034 if (!data->unique()) {
bungeman6e45bda2016-07-25 15:11:49 -070035 dataCopy = SkData::MakeWithCopy(data->data(), data->size());
reed42943c82016-09-12 12:01:44 -070036 data = dataCopy.get();
bungeman6e45bda2016-07-25 15:11:49 -070037 }
reed42943c82016-09-12 12:01:44 -070038 SkSFNTHeader* sfntHeader = static_cast<SkSFNTHeader*>(data->writable_data());
bungeman6e45bda2016-07-25 15:11:49 -070039
40 SkSFNTHeader::TableDirectoryEntry* tableEntry =
41 SkTAfter<SkSFNTHeader::TableDirectoryEntry>(sfntHeader);
42 SkSFNTHeader::TableDirectoryEntry* os2TableEntry = nullptr;
43 int numTables = SkEndian_SwapBE16(sfntHeader->numTables);
44 for (int tableEntryIndex = 0; tableEntryIndex < numTables; ++tableEntryIndex) {
45 if (SkOTTableOS2::TAG == tableEntry[tableEntryIndex].tag) {
46 os2TableEntry = tableEntry + tableEntryIndex;
47 break;
48 }
49 }
50 SkASSERT_RELEASE(os2TableEntry);
51
52 size_t os2TableOffset = SkEndian_SwapBE32(os2TableEntry->offset);
53 SkOTTableOS2_V0* os2Table = SkTAddOffset<SkOTTableOS2_V0>(sfntHeader, os2TableOffset);
54 os2Table->usWeightClass.value = SkEndian_SwapBE16(weight);
55 using WidthType = SkOTTableOS2_V0::WidthClass::Value;
56 os2Table->usWidthClass.value = static_cast<WidthType>(SkEndian_SwapBE16(width));
57
Mike Reed271d1d92018-09-03 21:10:10 -040058 sk_sp<SkTypeface> newTypeface(SkTypeface::MakeFromData(sk_ref_sp(data)));
Mike Kleincb6940b2017-11-09 13:45:10 -050059 if (!newTypeface) {
60 // Not all SkFontMgr can MakeFromStream().
61 return;
62 }
bungeman6e45bda2016-07-25 15:11:49 -070063
64 SkFontStyle newStyle = newTypeface->fontStyle();
65
66 //printf("%d, %f\n", weight, (newStyle.weight() - (float)0x7FFF) / (float)0x7FFF);
67 //printf("%d, %f\n", width , (newStyle.width() - (float)0x7F) / (float)0x7F);
68 //printf("%d, %d\n", weight, newStyle.weight());
69 //printf("%d, %d\n", width , newStyle.width());
70
71 // Some back-ends (CG, GDI, DW) support OS/2 version A which uses 0 - 10 (but all differently).
72 REPORTER_ASSERT(reporter,
73 newStyle.weight() == weight ||
74 (weight <= 10 && newStyle.weight() == 100 * weight) ||
75 (weight == 4 && newStyle.weight() == 350) || // GDI weirdness
76 (weight == 5 && newStyle.weight() == 400) || // GDI weirdness
77 (weight == 0 && newStyle.weight() == 1) || // DW weirdness
78 (weight == 1000 && newStyle.weight() == 999) // DW weirdness
79 );
80
81 // Some back-ends (GDI) don't support width, ensure these always report 'medium'.
82 REPORTER_ASSERT(reporter,
83 newStyle.width() == width ||
84 newStyle.width() == 5);
85}
86DEF_TEST(TypefaceStyle, reporter) {
Hal Canary53e5e7d2017-12-08 14:25:14 -050087 std::unique_ptr<SkStreamAsset> stream(GetResourceAsStream("fonts/Em.ttf"));
bungeman6e45bda2016-07-25 15:11:49 -070088 if (!stream) {
Hal Canary53e5e7d2017-12-08 14:25:14 -050089 REPORT_FAILURE(reporter, "fonts/Em.ttf", SkString("Cannot load resource"));
bungeman6e45bda2016-07-25 15:11:49 -070090 return;
91 }
92 sk_sp<SkData> data(SkData::MakeFromStream(stream.get(), stream->getLength()));
93
94 using SkFS = SkFontStyle;
95 for (int weight = SkFS::kInvisible_Weight; weight <= SkFS::kExtraBlack_Weight; ++weight) {
96 TypefaceStyle_test(reporter, weight, 5, data.get());
97 }
bungemand783e082016-08-01 12:37:13 -070098 for (int width = SkFS::kUltraCondensed_Width; width <= SkFS::kUltraExpanded_Width; ++width) {
bungeman6e45bda2016-07-25 15:11:49 -070099 TypefaceStyle_test(reporter, 400, width, data.get());
100 }
101}
102
Ben Wagner03cd6e62018-03-08 16:02:55 -0500103DEF_TEST(TypefaceRoundTrip, reporter) {
104 sk_sp<SkTypeface> typeface(MakeResourceAsTypeface("fonts/7630.otf"));
105 if (!typeface) {
106 // Not all SkFontMgr can MakeFromStream().
107 return;
108 }
109
110 int fontIndex;
Ben Wagnerff84d8a2019-02-26 15:39:41 -0500111 std::unique_ptr<SkStreamAsset> stream = typeface->openStream(&fontIndex);
Ben Wagner03cd6e62018-03-08 16:02:55 -0500112
113 sk_sp<SkFontMgr> fm = SkFontMgr::RefDefault();
114 sk_sp<SkTypeface> typeface2 = fm->makeFromStream(std::move(stream), fontIndex);
115 REPORTER_ASSERT(reporter, typeface2);
116}
117
Ben Wagner255ab8d2016-10-07 15:50:53 -0400118DEF_TEST(FontDescriptorNegativeVariationSerialize, reporter) {
119 SkFontDescriptor desc;
120 SkFixed axis = -SK_Fixed1;
Mike Kleinf46d5ca2019-12-11 10:45:01 -0500121 auto font = std::make_unique<SkMemoryStream>("a", 1, false);
122 desc.setFontData(std::make_unique<SkFontData>(std::move(font), 0, &axis, 1));
Ben Wagner255ab8d2016-10-07 15:50:53 -0400123
124 SkDynamicMemoryWStream stream;
125 desc.serialize(&stream);
126 SkFontDescriptor descD;
127 SkFontDescriptor::Deserialize(stream.detachAsStream().get(), &descD);
128 std::unique_ptr<SkFontData> fontData = descD.detachFontData();
129 if (!fontData) {
130 REPORT_FAILURE(reporter, "fontData", SkString());
131 return;
132 }
133
134 if (fontData->getAxisCount() != 1) {
135 REPORT_FAILURE(reporter, "fontData->getAxisCount() != 1", SkString());
136 return;
137 }
138
139 REPORTER_ASSERT(reporter, fontData->getAxis()[0] == -SK_Fixed1);
140};
141
Ben Wagnerfc497342017-02-24 11:15:26 -0500142DEF_TEST(TypefaceAxes, reporter) {
Hal Canary53e5e7d2017-12-08 14:25:14 -0500143 std::unique_ptr<SkStreamAsset> distortable(GetResourceAsStream("fonts/Distortable.ttf"));
Ben Wagnerfc497342017-02-24 11:15:26 -0500144 if (!distortable) {
145 REPORT_FAILURE(reporter, "distortable", SkString());
146 return;
147 }
bungeman9aec8942017-03-29 13:38:53 -0400148 constexpr int numberOfAxesInDistortable = 1;
Ben Wagnerfc497342017-02-24 11:15:26 -0500149
150 sk_sp<SkFontMgr> fm = SkFontMgr::RefDefault();
bungeman9aec8942017-03-29 13:38:53 -0400151 // The position may be over specified. If there are multiple values for a given axis,
152 // ensure the last one since that's what css-fonts-4 requires.
Ben Wagnerfc497342017-02-24 11:15:26 -0500153 const SkFontArguments::VariationPosition::Coordinate position[] = {
bungeman9aec8942017-03-29 13:38:53 -0400154 { SkSetFourByteTag('w','g','h','t'), 1.618033988749895f },
155 { SkSetFourByteTag('w','g','h','t'), SK_ScalarSqrt2 },
Ben Wagnerfc497342017-02-24 11:15:26 -0500156 };
157 SkFontArguments params;
158 params.setVariationDesignPosition({position, SK_ARRAY_COUNT(position)});
159 // TODO: if axes are set and the back-end doesn't support them, should we create the typeface?
Mike Reed59227392017-09-26 09:46:08 -0400160 sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(distortable), params);
Ben Wagnerfc497342017-02-24 11:15:26 -0500161
Mike Kleincb6940b2017-11-09 13:45:10 -0500162 if (!typeface) {
Ben Wagnerab51c2c2019-12-11 15:30:34 -0500163 return; // Not all SkFontMgr can makeFromStream().
Mike Kleincb6940b2017-11-09 13:45:10 -0500164 }
165
Ben Wagnerfc497342017-02-24 11:15:26 -0500166 int count = typeface->getVariationDesignPosition(nullptr, 0);
167 if (count == -1) {
Ben Wagnerab51c2c2019-12-11 15:30:34 -0500168 return; // The number of axes is unknown.
Ben Wagnerfc497342017-02-24 11:15:26 -0500169 }
bungeman9aec8942017-03-29 13:38:53 -0400170 REPORTER_ASSERT(reporter, count == numberOfAxesInDistortable);
Ben Wagnerfc497342017-02-24 11:15:26 -0500171
bungeman9aec8942017-03-29 13:38:53 -0400172 SkFontArguments::VariationPosition::Coordinate positionRead[numberOfAxesInDistortable];
Ben Wagnerfc497342017-02-24 11:15:26 -0500173 count = typeface->getVariationDesignPosition(positionRead, SK_ARRAY_COUNT(positionRead));
Ben Wagnerab51c2c2019-12-11 15:30:34 -0500174 if (count == -1) {
175 return; // The position cannot be determined.
176 }
bungeman9aec8942017-03-29 13:38:53 -0400177 REPORTER_ASSERT(reporter, count == SK_ARRAY_COUNT(positionRead));
Ben Wagnerfc497342017-02-24 11:15:26 -0500178
bungeman9aec8942017-03-29 13:38:53 -0400179 REPORTER_ASSERT(reporter, positionRead[0].axis == position[1].axis);
Ben Wagnerfc497342017-02-24 11:15:26 -0500180
181 // Convert to fixed for "almost equal".
182 SkFixed fixedRead = SkScalarToFixed(positionRead[0].value);
bungeman9aec8942017-03-29 13:38:53 -0400183 SkFixed fixedOriginal = SkScalarToFixed(position[1].value);
Ben Wagnerab51c2c2019-12-11 15:30:34 -0500184 REPORTER_ASSERT(reporter, SkTAbs(fixedRead - fixedOriginal) < 2 || // variation set correctly
185 SkTAbs(fixedRead - SK_Fixed1 ) < 2); // variation remained default
Ben Wagnerfc497342017-02-24 11:15:26 -0500186}
187
188DEF_TEST(TypefaceVariationIndex, reporter) {
Hal Canary53e5e7d2017-12-08 14:25:14 -0500189 std::unique_ptr<SkStreamAsset> distortable(GetResourceAsStream("fonts/Distortable.ttf"));
Ben Wagnerfc497342017-02-24 11:15:26 -0500190 if (!distortable) {
191 REPORT_FAILURE(reporter, "distortable", SkString());
192 return;
193 }
194
195 sk_sp<SkFontMgr> fm = SkFontMgr::RefDefault();
196 SkFontArguments params;
197 // The first named variation position in Distortable is 'Thin'.
198 params.setCollectionIndex(0x00010000);
Mike Reed59227392017-09-26 09:46:08 -0400199 sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(distortable), params);
Ben Wagnerfc497342017-02-24 11:15:26 -0500200 if (!typeface) {
201 // FreeType is the only weird thing that supports this, Skia just needs to make sure if it
202 // gets one of these things make sense.
203 return;
204 }
205
206 int count = typeface->getVariationDesignPosition(nullptr, 0);
207 if (!(count == 1)) {
208 REPORT_FAILURE(reporter, "count == 1", SkString());
209 return;
210 }
211
212 SkFontArguments::VariationPosition::Coordinate positionRead[1];
213 count = typeface->getVariationDesignPosition(positionRead, SK_ARRAY_COUNT(positionRead));
214 if (count == -1) {
215 return;
216 }
217 if (!(count == 1)) {
218 REPORT_FAILURE(reporter, "count == 1", SkString());
219 return;
220 }
221 REPORTER_ASSERT(reporter, positionRead[0].axis == SkSetFourByteTag('w','g','h','t'));
222 REPORTER_ASSERT(reporter, positionRead[0].value == 0.5);
223}
224
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000225DEF_TEST(Typeface, reporter) {
djsollen@google.com1f584ed2013-09-19 12:08:40 +0000226
mbocee6a9912016-05-31 11:42:36 -0700227 sk_sp<SkTypeface> t1(SkTypeface::MakeFromName(nullptr, SkFontStyle()));
Ben Wagner67ef5d72017-10-06 16:05:39 -0400228 sk_sp<SkTypeface> t2(SkTypeface::MakeDefault());
djsollen@google.com1f584ed2013-09-19 12:08:40 +0000229
230 REPORTER_ASSERT(reporter, SkTypeface::Equal(t1.get(), t2.get()));
Ben Wagnera93a14a2017-08-28 10:34:05 -0400231 REPORTER_ASSERT(reporter, SkTypeface::Equal(nullptr, t1.get()));
232 REPORTER_ASSERT(reporter, SkTypeface::Equal(nullptr, t2.get()));
233 REPORTER_ASSERT(reporter, SkTypeface::Equal(t1.get(), nullptr));
234 REPORTER_ASSERT(reporter, SkTypeface::Equal(t2.get(), nullptr));
djsollen@google.com1f584ed2013-09-19 12:08:40 +0000235}
bungeman82a455f2016-04-14 08:04:45 -0700236
Ben Wagnere346b1e2018-06-26 11:22:37 -0400237DEF_TEST(TypefaceAxesParameters, reporter) {
238 std::unique_ptr<SkStreamAsset> distortable(GetResourceAsStream("fonts/Distortable.ttf"));
239 if (!distortable) {
240 REPORT_FAILURE(reporter, "distortable", SkString());
241 return;
242 }
243 constexpr int numberOfAxesInDistortable = 1;
244 constexpr SkScalar minAxisInDistortable = 0.5;
245 constexpr SkScalar defAxisInDistortable = 1;
246 constexpr SkScalar maxAxisInDistortable = 2;
Ben Wagnerab51c2c2019-12-11 15:30:34 -0500247 constexpr bool axisIsHiddenInDistortable = true;
Ben Wagnere346b1e2018-06-26 11:22:37 -0400248
249 sk_sp<SkFontMgr> fm = SkFontMgr::RefDefault();
250
251 SkFontArguments params;
252 sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(distortable), params);
253
254 if (!typeface) {
Ben Wagnerab51c2c2019-12-11 15:30:34 -0500255 return; // Not all SkFontMgr can makeFromStream().
Ben Wagnere346b1e2018-06-26 11:22:37 -0400256 }
257
258 SkFontParameters::Variation::Axis parameter[numberOfAxesInDistortable];
259 int count = typeface->getVariationDesignParameters(parameter, SK_ARRAY_COUNT(parameter));
260 if (count == -1) {
261 return;
262 }
263
264 REPORTER_ASSERT(reporter, count == SK_ARRAY_COUNT(parameter));
265 REPORTER_ASSERT(reporter, parameter[0].min == minAxisInDistortable);
266 REPORTER_ASSERT(reporter, parameter[0].def == defAxisInDistortable);
267 REPORTER_ASSERT(reporter, parameter[0].max == maxAxisInDistortable);
268 REPORTER_ASSERT(reporter, parameter[0].tag == SkSetFourByteTag('w','g','h','t'));
Ben Wagnerab51c2c2019-12-11 15:30:34 -0500269 // This seems silly, but allows MSAN to ensure that isHidden is initialized.
270 // With GDI or before macOS 10.12, Win10, or FreeType 2.8.1 the API for hidden is missing.
271 REPORTER_ASSERT(reporter, parameter[0].isHidden() == axisIsHiddenInDistortable ||
272 parameter[0].isHidden() == false);
Ben Wagnere346b1e2018-06-26 11:22:37 -0400273}
274
bungeman82a455f2016-04-14 08:04:45 -0700275static bool count_proc(SkTypeface* face, void* ctx) {
276 int* count = static_cast<int*>(ctx);
277 *count = *count + 1;
278 return false;
279}
280static int count(skiatest::Reporter* reporter, const SkTypefaceCache& cache) {
281 int count = 0;
Ben Wagner68efb212019-03-04 16:15:40 -0500282 sk_sp<SkTypeface> none = cache.findByProcAndRef(count_proc, &count);
bungeman82a455f2016-04-14 08:04:45 -0700283 REPORTER_ASSERT(reporter, none == nullptr);
284 return count;
285}
286
287DEF_TEST(TypefaceCache, reporter) {
Mike Klein0cffcbf92019-03-20 11:08:46 -0500288 sk_sp<SkTypeface> t1(TestEmptyTypeface::Make());
bungeman82a455f2016-04-14 08:04:45 -0700289 {
290 SkTypefaceCache cache;
291 REPORTER_ASSERT(reporter, count(reporter, cache) == 0);
292 {
Mike Klein0cffcbf92019-03-20 11:08:46 -0500293 sk_sp<SkTypeface> t0(TestEmptyTypeface::Make());
Ben Wagner68efb212019-03-04 16:15:40 -0500294 cache.add(t0);
bungeman82a455f2016-04-14 08:04:45 -0700295 REPORTER_ASSERT(reporter, count(reporter, cache) == 1);
Ben Wagner68efb212019-03-04 16:15:40 -0500296 cache.add(t1);
bungeman82a455f2016-04-14 08:04:45 -0700297 REPORTER_ASSERT(reporter, count(reporter, cache) == 2);
298 cache.purgeAll();
299 REPORTER_ASSERT(reporter, count(reporter, cache) == 2);
300 }
301 REPORTER_ASSERT(reporter, count(reporter, cache) == 2);
302 cache.purgeAll();
303 REPORTER_ASSERT(reporter, count(reporter, cache) == 1);
304 }
305 REPORTER_ASSERT(reporter, t1->unique());
306}
Mike Reedbf677412018-09-03 12:34:54 -0400307
308static void check_serialize_behaviors(sk_sp<SkTypeface> tf, bool isLocalData,
309 skiatest::Reporter* reporter) {
310 if (!tf) {
311 return;
312 }
313 auto data0 = tf->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
314 auto data1 = tf->serialize(SkTypeface::SerializeBehavior::kDontIncludeData);
315 auto data2 = tf->serialize(SkTypeface::SerializeBehavior::kIncludeDataIfLocal);
316
317 REPORTER_ASSERT(reporter, data0->size() >= data1->size());
318
319 if (isLocalData) {
320 REPORTER_ASSERT(reporter, data0->equals(data2.get()));
321 } else {
322 REPORTER_ASSERT(reporter, data1->equals(data2.get()));
323 }
324}
325
326DEF_TEST(Typeface_serialize, reporter) {
327 check_serialize_behaviors(SkTypeface::MakeDefault(), false, reporter);
328 check_serialize_behaviors(SkTypeface::MakeFromStream(
Mike Reed271d1d92018-09-03 21:10:10 -0400329 GetResourceAsStream("fonts/Distortable.ttf")),
Mike Reedbf677412018-09-03 12:34:54 -0400330 true, reporter);
331
332}
333
Ben Wagnera541db4d2019-05-22 17:33:07 -0400334DEF_TEST(Typeface_glyph_to_char, reporter) {
335 SkFont font(ToolUtils::emoji_typeface(), 12);
336 SkASSERT(font.getTypeface());
337 char const * text = ToolUtils::emoji_sample_text();
338 size_t const textLen = strlen(text);
339 size_t const codepointCount = SkUTF::CountUTF8(text, textLen);
340 char const * const textEnd = text + textLen;
341 std::unique_ptr<SkUnichar[]> originalCodepoints(new SkUnichar[codepointCount]);
342 for (size_t i = 0; i < codepointCount; ++i) {
343 originalCodepoints[i] = SkUTF::NextUTF8(&text, textEnd);
344 }
345 std::unique_ptr<SkGlyphID[]> glyphs(new SkGlyphID[codepointCount]);
346 font.unicharsToGlyphs(originalCodepoints.get(), codepointCount, glyphs.get());
347
348 std::unique_ptr<SkUnichar[]> newCodepoints(new SkUnichar[codepointCount]);
349 SkFontPriv::GlyphsToUnichars(font, glyphs.get(), codepointCount, newCodepoints.get());
350
351 SkString familyName;
352 font.getTypeface()->getFamilyName(&familyName);
353 for (size_t i = 0; i < codepointCount; ++i) {
354#if defined(SK_BUILD_FOR_WIN)
355 // GDI does not support character to glyph mapping outside BMP.
356 if (gSkFontMgr_DefaultFactory == &SkFontMgr_New_GDI &&
357 0xFFFF < originalCodepoints[i] && newCodepoints[i] == 0)
358 {
359 continue;
360 }
361#endif
362 // If two codepoints map to the same glyph then this assert is not valid.
363 // However, the emoji test font should never have multiple characters map to the same glyph.
364 REPORTER_ASSERT(reporter, originalCodepoints[i] == newCodepoints[i],
Adlai Holler684838f2020-05-12 10:41:04 -0400365 "name:%s i:%zu original:%d new:%d glyph:%d", familyName.c_str(), i,
Ben Wagnera541db4d2019-05-22 17:33:07 -0400366 originalCodepoints[i], newCodepoints[i], glyphs[i]);
367 }
368}
Mike Reed40d9c512019-06-10 11:34:23 -0400369
370// This test makes sure the legacy typeface creation does not lose its specified
371// style. See https://bugs.chromium.org/p/skia/issues/detail?id=8447 for more
372// context.
373DEF_TEST(LegacyMakeTypeface, reporter) {
374 sk_sp<SkFontMgr> fm = SkFontMgr::RefDefault();
375 sk_sp<SkTypeface> typeface1 = fm->legacyMakeTypeface(nullptr, SkFontStyle::Italic());
376 sk_sp<SkTypeface> typeface2 = fm->legacyMakeTypeface(nullptr, SkFontStyle::Bold());
377 sk_sp<SkTypeface> typeface3 = fm->legacyMakeTypeface(nullptr, SkFontStyle::BoldItalic());
378
379 REPORTER_ASSERT(reporter, typeface1->isItalic());
380 REPORTER_ASSERT(reporter, !typeface1->isBold());
381 REPORTER_ASSERT(reporter, !typeface2->isItalic());
382 REPORTER_ASSERT(reporter, typeface2->isBold());
383 REPORTER_ASSERT(reporter, typeface3->isItalic());
384 REPORTER_ASSERT(reporter, typeface3->isBold());
385}