• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
8 #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"
13 #include "include/ports/SkTypeface_win.h"
14 #include "include/private/SkFixed.h"
15 #include "src/core/SkAdvancedTypefaceMetrics.h"
16 #include "src/core/SkFontDescriptor.h"
17 #include "src/core/SkFontMgrPriv.h"
18 #include "src/core/SkFontPriv.h"
19 #include "src/core/SkTypefaceCache.h"
20 #include "src/sfnt/SkOTTable_OS_2.h"
21 #include "src/sfnt/SkSFNTHeader.h"
22 #include "src/utils/SkUTF.h"
23 #include "tests/Test.h"
24 #include "tools/Resources.h"
25 #include "tools/ToolUtils.h"
26 #include "tools/fonts/TestEmptyTypeface.h"
27 
28 #include <memory>
29 
TypefaceStyle_test(skiatest::Reporter * reporter,uint16_t weight,uint16_t width,SkData * data)30 static void TypefaceStyle_test(skiatest::Reporter* reporter,
31                                uint16_t weight, uint16_t width, SkData* data)
32 {
33     sk_sp<SkData> dataCopy;
34     if (!data->unique()) {
35         dataCopy = SkData::MakeWithCopy(data->data(), data->size());
36         data = dataCopy.get();
37     }
38     SkSFNTHeader* sfntHeader = static_cast<SkSFNTHeader*>(data->writable_data());
39 
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 
58     sk_sp<SkTypeface> newTypeface(SkTypeface::MakeFromData(sk_ref_sp(data)));
59     if (!newTypeface) {
60         // Not all SkFontMgr can MakeFromStream().
61         return;
62     }
63 
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 }
DEF_TEST(TypefaceStyle,reporter)86 DEF_TEST(TypefaceStyle, reporter) {
87     std::unique_ptr<SkStreamAsset> stream(GetResourceAsStream("fonts/Em.ttf"));
88     if (!stream) {
89         REPORT_FAILURE(reporter, "fonts/Em.ttf", SkString("Cannot load resource"));
90         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     }
98     for (int width = SkFS::kUltraCondensed_Width; width <= SkFS::kUltraExpanded_Width; ++width) {
99         TypefaceStyle_test(reporter, 400, width, data.get());
100     }
101 }
102 
DEF_TEST(TypefacePostScriptName,reporter)103 DEF_TEST(TypefacePostScriptName, reporter) {
104     sk_sp<SkTypeface> typeface(MakeResourceAsTypeface("fonts/Em.ttf"));
105     if (!typeface) {
106         // Not all SkFontMgr can MakeFromStream().
107         return;
108     }
109 
110     SkString postScriptName;
111     bool hasName = typeface->getPostScriptName(&postScriptName);
112     bool hasName2 = typeface->getPostScriptName(nullptr);
113     REPORTER_ASSERT(reporter, hasName == hasName2);
114     if (hasName) {
115         REPORTER_ASSERT(reporter, postScriptName == SkString("Em"));
116     }
117 }
118 
DEF_TEST(TypefaceRoundTrip,reporter)119 DEF_TEST(TypefaceRoundTrip, reporter) {
120     sk_sp<SkTypeface> typeface(MakeResourceAsTypeface("fonts/7630.otf"));
121     if (!typeface) {
122         // Not all SkFontMgr can MakeFromStream().
123         return;
124     }
125 
126     int fontIndex;
127     std::unique_ptr<SkStreamAsset> stream = typeface->openStream(&fontIndex);
128 
129     sk_sp<SkFontMgr> fm = SkFontMgr::RefDefault();
130     sk_sp<SkTypeface> typeface2 = fm->makeFromStream(std::move(stream), fontIndex);
131     REPORTER_ASSERT(reporter, typeface2);
132 }
133 
DEF_TEST(FontDescriptorNegativeVariationSerialize,reporter)134 DEF_TEST(FontDescriptorNegativeVariationSerialize, reporter) {
135     SkFontDescriptor desc;
136     SkFontArguments::VariationPosition::Coordinate* variation = desc.setVariationCoordinates(1);
137     variation[0] = { 0, -1.0f };
138 
139     SkDynamicMemoryWStream stream;
140     desc.serialize(&stream);
141     SkFontDescriptor descD;
142     SkFontDescriptor::Deserialize(stream.detachAsStream().get(), &descD);
143 
144     if (descD.getVariationCoordinateCount() != 1) {
145         REPORT_FAILURE(reporter, "descD.getVariationCoordinateCount() != 1", SkString());
146         return;
147     }
148 
149     REPORTER_ASSERT(reporter, descD.getVariation()[0].value == -1.0f);
150 };
151 
DEF_TEST(TypefaceAxes,reporter)152 DEF_TEST(TypefaceAxes, reporter) {
153     using Variation = SkFontArguments::VariationPosition;
154     // In DWrite in at least up to 1901 18363.1198 IDWriteFontFace5::GetFontAxisValues and
155     // GetFontAxisValueCount along with IDWriteFontResource::GetFontAxisAttributes and
156     // GetFontAxisCount (and related) seem to incorrectly collapse multiple axes with the same tag.
157     // Since this is a limitation of the underlying implementation, for now allow the test to pass
158     // with the axis tag count (as opposed to the axis count). Eventually all implementations should
159     // pass this test without 'alsoAcceptedAxisTagCount'.
160     auto test = [&](SkTypeface* typeface, const Variation& expected, int alsoAcceptedAxisTagCount) {
161         if (!typeface) {
162             return;  // Not all SkFontMgr can makeFromStream().
163         }
164 
165         int actualCount = typeface->getVariationDesignPosition(nullptr, 0);
166         if (actualCount == -1) {
167             return;  // The number of axes is unknown.
168         }
169         REPORTER_ASSERT(reporter, actualCount == expected.coordinateCount ||
170                                   actualCount == alsoAcceptedAxisTagCount);
171 
172         // Variable font conservative bounds don't vary, so ensure they aren't reported.
173         REPORTER_ASSERT(reporter, typeface->getBounds().isEmpty());
174 
175         std::unique_ptr<Variation::Coordinate[]> actual(new Variation::Coordinate[actualCount]);
176         actualCount = typeface->getVariationDesignPosition(actual.get(), actualCount);
177         if (actualCount == -1) {
178             return;  // The position cannot be determined.
179         }
180         REPORTER_ASSERT(reporter, actualCount == expected.coordinateCount ||
181                                   actualCount == alsoAcceptedAxisTagCount);
182 
183         // Every actual must be expected.
184         std::unique_ptr<bool[]> expectedUsed(new bool[expected.coordinateCount]());
185         for (int actualIdx = 0; actualIdx < actualCount; ++actualIdx) {
186             bool actualFound = false;
187             for (int expectedIdx = 0; expectedIdx < expected.coordinateCount; ++expectedIdx) {
188                 if (expectedUsed[expectedIdx]) {
189                     continue;
190                 }
191 
192                 if (actual[actualIdx].axis != expected.coordinates[expectedIdx].axis) {
193                     continue;
194                 }
195 
196                 // Convert to fixed for "almost equal".
197                 SkFixed fixedRead = SkScalarToFixed(actual[actualIdx].value);
198                 SkFixed fixedOriginal = SkScalarToFixed(expected.coordinates[expectedIdx].value);
199                 if (!(SkTAbs(fixedRead - fixedOriginal) < 2)) {
200                     continue;
201                 }
202 
203                 // This actual matched an unused expected.
204                 actualFound = true;
205                 expectedUsed[expectedIdx] = true;
206                 break;
207             }
208             REPORTER_ASSERT(reporter, actualFound,
209                 "Actual axis '%c%c%c%c' with value '%f' not expected",
210                 (actual[actualIdx].axis >> 24) & 0xFF,
211                 (actual[actualIdx].axis >> 16) & 0xFF,
212                 (actual[actualIdx].axis >>  8) & 0xFF,
213                 (actual[actualIdx].axis      ) & 0xFF,
214                 SkScalarToDouble(actual[actualIdx].value));
215         }
216     };
217 
218     sk_sp<SkFontMgr> fm = SkFontMgr::RefDefault();
219 
220     // Not specifying a position should produce the default.
221     {
222         std::unique_ptr<SkStreamAsset> variable(GetResourceAsStream("fonts/Variable.ttf"));
223         if (!variable) {
224             REPORT_FAILURE(reporter, "variable", SkString());
225             return;
226         }
227         const Variation::Coordinate defaultPosition[] = {
228             { SkSetFourByteTag('w','g','h','t'), 400.0f },
229             { SkSetFourByteTag('w','d','t','h'), 100.0f },
230         };
231         sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(variable), 0);
232         test(typeface.get(), Variation{&defaultPosition[0], 2}, -1);
233     }
234 
235     // Multiple axes with the same tag (and min, max, default) works.
236     {
237         std::unique_ptr<SkStreamAsset> dupTags(GetResourceAsStream("fonts/VaryAlongQuads.ttf"));
238         if (!dupTags) {
239             REPORT_FAILURE(reporter, "dupTags", SkString());
240             return;
241         }
242 
243         // The position may be over specified. If there are multiple values for a given axis,
244         // ensure the last one since that's what css-fonts-4 requires.
245         const Variation::Coordinate position[] = {
246             { SkSetFourByteTag('w','g','h','t'), 700.0f },
247             { SkSetFourByteTag('w','g','h','t'), 600.0f },
248             { SkSetFourByteTag('w','g','h','t'), 600.0f },
249         };
250         SkFontArguments params;
251         params.setVariationDesignPosition({position, SK_ARRAY_COUNT(position)});
252         sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(dupTags), params);
253         test(typeface.get(), Variation{&position[1], 2}, 1);
254     }
255 
256     // Overspecifying an axis tag value applies the last one in the list.
257     {
258         std::unique_ptr<SkStreamAsset> distortable(GetResourceAsStream("fonts/Distortable.ttf"));
259         if (!distortable) {
260             REPORT_FAILURE(reporter, "distortable", SkString());
261             return;
262         }
263 
264         // The position may be over specified. If there are multiple values for a given axis,
265         // ensure the last one since that's what css-fonts-4 requires.
266         const Variation::Coordinate position[] = {
267             { SkSetFourByteTag('w','g','h','t'), 1.618033988749895f },
268             { SkSetFourByteTag('w','g','h','t'), SK_ScalarSqrt2 },
269         };
270         SkFontArguments params;
271         params.setVariationDesignPosition({position, SK_ARRAY_COUNT(position)});
272         sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(distortable), params);
273         test(typeface.get(), Variation{&position[1], 1}, -1);
274 
275         if (typeface) {
276             // Cloning without specifying any parameters should produce an equivalent variation.
277             sk_sp<SkTypeface> clone = typeface->makeClone(SkFontArguments());
278             test(clone.get(), Variation{&position[1], 1}, -1);
279         }
280     }
281 }
282 
DEF_TEST(TypefaceVariationIndex,reporter)283 DEF_TEST(TypefaceVariationIndex, reporter) {
284     std::unique_ptr<SkStreamAsset> distortable(GetResourceAsStream("fonts/Distortable.ttf"));
285     if (!distortable) {
286         REPORT_FAILURE(reporter, "distortable", SkString());
287         return;
288     }
289 
290     sk_sp<SkFontMgr> fm = SkFontMgr::RefDefault();
291     SkFontArguments params;
292     // The first named variation position in Distortable is 'Thin'.
293     params.setCollectionIndex(0x00010000);
294     sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(distortable), params);
295     if (!typeface) {
296         // FreeType is the only weird thing that supports this, Skia just needs to make sure if it
297         // gets one of these things make sense.
298         return;
299     }
300 
301     int count = typeface->getVariationDesignPosition(nullptr, 0);
302     if (!(count == 1)) {
303         REPORT_FAILURE(reporter, "count == 1", SkString());
304         return;
305     }
306 
307     SkFontArguments::VariationPosition::Coordinate positionRead[1];
308     count = typeface->getVariationDesignPosition(positionRead, SK_ARRAY_COUNT(positionRead));
309     if (count == -1) {
310         return;
311     }
312     if (!(count == 1)) {
313         REPORT_FAILURE(reporter, "count == 1", SkString());
314         return;
315     }
316     REPORTER_ASSERT(reporter, positionRead[0].axis == SkSetFourByteTag('w','g','h','t'));
317     REPORTER_ASSERT(reporter, positionRead[0].value == 0.5);
318 }
319 
DEF_TEST(Typeface,reporter)320 DEF_TEST(Typeface, reporter) {
321 
322     sk_sp<SkTypeface> t1(SkTypeface::MakeFromName(nullptr, SkFontStyle()));
323     sk_sp<SkTypeface> t2(SkTypeface::MakeDefault());
324 
325     REPORTER_ASSERT(reporter, SkTypeface::Equal(t1.get(), t2.get()));
326     REPORTER_ASSERT(reporter, SkTypeface::Equal(nullptr, t1.get()));
327     REPORTER_ASSERT(reporter, SkTypeface::Equal(nullptr, t2.get()));
328     REPORTER_ASSERT(reporter, SkTypeface::Equal(t1.get(), nullptr));
329     REPORTER_ASSERT(reporter, SkTypeface::Equal(t2.get(), nullptr));
330 }
331 
DEF_TEST(TypefaceAxesParameters,reporter)332 DEF_TEST(TypefaceAxesParameters, reporter) {
333     using Axis = SkFontParameters::Variation::Axis;
334 
335     // In DWrite in at least up to 1901 18363.1198 IDWriteFontFace5::GetFontAxisValues and
336     // GetFontAxisValueCount along with IDWriteFontResource::GetFontAxisAttributes and
337     // GetFontAxisCount (and related) seem to incorrectly collapse multiple axes with the same tag.
338     // Since this is a limitation of the underlying implementation, for now allow the test to pass
339     // with the axis tag count (as opposed to the axis count). Eventually all implementations should
340     // pass this test without 'alsoAcceptedAxisTagCount'.
341     auto test = [&](SkTypeface* typeface, const Axis* expected, int expectedCount,
342                     int alsoAcceptedAxisTagCount)
343     {
344         if (!typeface) {
345             return;  // Not all SkFontMgr can makeFromStream().
346         }
347 
348         int actualCount = typeface->getVariationDesignParameters(nullptr, 0);
349         if (actualCount == -1) {
350             return;  // The number of axes is unknown.
351         }
352         REPORTER_ASSERT(reporter, actualCount == expectedCount ||
353                                   actualCount == alsoAcceptedAxisTagCount);
354 
355         std::unique_ptr<Axis[]> actual(new Axis[actualCount]);
356         actualCount = typeface->getVariationDesignParameters(actual.get(), actualCount);
357         if (actualCount == -1) {
358             return;  // The position cannot be determined.
359         }
360         REPORTER_ASSERT(reporter, actualCount == expectedCount ||
361                                   actualCount == alsoAcceptedAxisTagCount);
362 
363         // Every actual must be expected.
364         std::unique_ptr<bool[]> expectedUsed(new bool[expectedCount]());
365         for (int actualIdx = 0; actualIdx < actualCount; ++actualIdx) {
366             bool actualFound = false;
367             for (int expectedIdx = 0; expectedIdx < expectedCount; ++expectedIdx) {
368                 if (expectedUsed[expectedIdx]) {
369                     continue;
370                 }
371 
372                 if (actual[actualIdx].tag != expected[expectedIdx].tag) {
373                     continue;
374                 }
375 
376                 // Convert to fixed for "almost equal".
377                 SkFixed fixedActualMin = SkScalarToFixed(actual[actualIdx].min);
378                 SkFixed fixedExpectedMin = SkScalarToFixed(expected[expectedIdx].min);
379                 if (!(SkTAbs(fixedActualMin - fixedExpectedMin) < 2)) {
380                     continue;
381                 }
382 
383                 SkFixed fixedActualMax = SkScalarToFixed(actual[actualIdx].max);
384                 SkFixed fixedExpectedMax = SkScalarToFixed(expected[expectedIdx].max);
385                 if (!(SkTAbs(fixedActualMax - fixedExpectedMax) < 2)) {
386                     continue;
387                 }
388 
389                 SkFixed fixedActualDefault = SkScalarToFixed(actual[actualIdx].def);
390                 SkFixed fixedExpectedDefault = SkScalarToFixed(expected[expectedIdx].def);
391                 if (!(SkTAbs(fixedActualDefault - fixedExpectedDefault) < 2)) {
392                     continue;
393                 }
394 
395                 // This seems silly, but allows MSAN to ensure that isHidden is initialized.
396                 // In GDI or before macOS 10.12, Win10, or FreeType 2.8.1 API for hidden is missing.
397                 if (actual[actualIdx].isHidden() &&
398                     actual[actualIdx].isHidden() != expected[expectedIdx].isHidden())
399                 {
400                     continue;
401                 }
402 
403                 // This actual matched an unused expected.
404                 actualFound = true;
405                 expectedUsed[expectedIdx] = true;
406                 break;
407             }
408             REPORTER_ASSERT(reporter, actualFound,
409                 "Actual axis '%c%c%c%c' with min %f max %f default %f hidden %s not expected",
410                 (actual[actualIdx].tag >> 24) & 0xFF,
411                 (actual[actualIdx].tag >> 16) & 0xFF,
412                 (actual[actualIdx].tag >>  8) & 0xFF,
413                 (actual[actualIdx].tag      ) & 0xFF,
414                 actual[actualIdx].min,
415                 actual[actualIdx].def,
416                 actual[actualIdx].max,
417                 actual[actualIdx].isHidden() ? "true" : "false");
418         }
419     };
420 
421     sk_sp<SkFontMgr> fm = SkFontMgr::RefDefault();
422 
423     // Two axis OpenType variable font.
424     {
425         std::unique_ptr<SkStreamAsset> variable(GetResourceAsStream("fonts/Variable.ttf"));
426         if (!variable) {
427             REPORT_FAILURE(reporter, "variable", SkString());
428             return;
429         }
430         constexpr Axis expected[] = {
431             Axis(SkSetFourByteTag('w','g','h','t'), 100.0f, 400.0f, 900.0f, true ),
432             Axis(SkSetFourByteTag('w','d','t','h'),  50.0f, 100.0f, 200.0f, false),
433         };
434         sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(variable), 0);
435         test(typeface.get(), &expected[0], SK_ARRAY_COUNT(expected), -1);
436     }
437 
438     // Multiple axes with the same tag (and min, max, default) works.
439     {
440         std::unique_ptr<SkStreamAsset> dupTags(GetResourceAsStream("fonts/VaryAlongQuads.ttf"));
441         if (!dupTags) {
442             REPORT_FAILURE(reporter, "dupTags", SkString());
443             return;
444         }
445 
446         // The position may be over specified. If there are multiple values for a given axis,
447         // ensure the last one since that's what css-fonts-4 requires.
448         constexpr Axis expected[] = {
449             Axis(SkSetFourByteTag('w','g','h','t'), 100.0f, 400.0f, 900.0f, false),
450             Axis(SkSetFourByteTag('w','g','h','t'), 100.0f, 400.0f, 900.0f, false),
451         };
452         sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(dupTags), 0);
453         test(typeface.get(), &expected[0], SK_ARRAY_COUNT(expected), 1);
454     }
455 
456     // Simple single axis GX variable font.
457     {
458         std::unique_ptr<SkStreamAsset> distortable(GetResourceAsStream("fonts/Distortable.ttf"));
459         if (!distortable) {
460             REPORT_FAILURE(reporter, "distortable", SkString());
461             return;
462         }
463         constexpr Axis expected[] = {
464             Axis(SkSetFourByteTag('w','g','h','t'), 0.5f, 1.0f, 2.0f, true),
465         };
466         sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(distortable), 0);
467         test(typeface.get(), &expected[0], SK_ARRAY_COUNT(expected), -1);
468     }
469 }
470 
count_proc(SkTypeface * face,void * ctx)471 static bool count_proc(SkTypeface* face, void* ctx) {
472     int* count = static_cast<int*>(ctx);
473     *count = *count + 1;
474     return false;
475 }
count(skiatest::Reporter * reporter,const SkTypefaceCache & cache)476 static int count(skiatest::Reporter* reporter, const SkTypefaceCache& cache) {
477     int count = 0;
478     sk_sp<SkTypeface> none = cache.findByProcAndRef(count_proc, &count);
479     REPORTER_ASSERT(reporter, none == nullptr);
480     return count;
481 }
482 
DEF_TEST(TypefaceCache,reporter)483 DEF_TEST(TypefaceCache, reporter) {
484     sk_sp<SkTypeface> t1(TestEmptyTypeface::Make());
485     {
486         SkTypefaceCache cache;
487         REPORTER_ASSERT(reporter, count(reporter, cache) == 0);
488         {
489             sk_sp<SkTypeface> t0(TestEmptyTypeface::Make());
490             cache.add(t0);
491             REPORTER_ASSERT(reporter, count(reporter, cache) == 1);
492             cache.add(t1);
493             REPORTER_ASSERT(reporter, count(reporter, cache) == 2);
494             cache.purgeAll();
495             REPORTER_ASSERT(reporter, count(reporter, cache) == 2);
496         }
497         REPORTER_ASSERT(reporter, count(reporter, cache) == 2);
498         cache.purgeAll();
499         REPORTER_ASSERT(reporter, count(reporter, cache) == 1);
500     }
501     REPORTER_ASSERT(reporter, t1->unique());
502 }
503 
check_serialize_behaviors(sk_sp<SkTypeface> tf,bool isLocalData,skiatest::Reporter * reporter)504 static void check_serialize_behaviors(sk_sp<SkTypeface> tf, bool isLocalData,
505                                       skiatest::Reporter* reporter) {
506     if (!tf) {
507         return;
508     }
509     auto data0 = tf->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
510     auto data1 = tf->serialize(SkTypeface::SerializeBehavior::kDontIncludeData);
511     auto data2 = tf->serialize(SkTypeface::SerializeBehavior::kIncludeDataIfLocal);
512 
513     REPORTER_ASSERT(reporter, data0->size() >= data1->size());
514 
515     if (isLocalData) {
516         REPORTER_ASSERT(reporter, !data0->equals(data2.get()));
517     } else {
518         REPORTER_ASSERT(reporter, data1->equals(data2.get()));
519     }
520 }
521 
DEF_TEST(Typeface_serialize,reporter)522 DEF_TEST(Typeface_serialize, reporter) {
523     check_serialize_behaviors(SkTypeface::MakeDefault(), false, reporter);
524     check_serialize_behaviors(SkTypeface::MakeFromStream(
525                                          GetResourceAsStream("fonts/Distortable.ttf")),
526                               true, reporter);
527 
528 }
529 
530 #ifdef SKIA_COMPILE_DM_ALL
DEF_TEST(Typeface_glyph_to_char,reporter)531 DEF_TEST(Typeface_glyph_to_char, reporter) {
532     SkFont font(ToolUtils::emoji_typeface(), 12);
533     SkASSERT(font.getTypeface());
534     char const * text = ToolUtils::emoji_sample_text();
535     size_t const textLen = strlen(text);
536     size_t const codepointCount = SkUTF::CountUTF8(text, textLen);
537     char const * const textEnd = text + textLen;
538     std::unique_ptr<SkUnichar[]> originalCodepoints(new SkUnichar[codepointCount]);
539     for (size_t i = 0; i < codepointCount; ++i) {
540         originalCodepoints[i] = SkUTF::NextUTF8(&text, textEnd);
541     }
542     std::unique_ptr<SkGlyphID[]> glyphs(new SkGlyphID[codepointCount]);
543     font.unicharsToGlyphs(originalCodepoints.get(), codepointCount, glyphs.get());
544 
545     std::unique_ptr<SkUnichar[]> newCodepoints(new SkUnichar[codepointCount]);
546     SkFontPriv::GlyphsToUnichars(font, glyphs.get(), codepointCount, newCodepoints.get());
547 
548     SkString familyName;
549     font.getTypeface()->getFamilyName(&familyName);
550     for (size_t i = 0; i < codepointCount; ++i) {
551 #if defined(SK_BUILD_FOR_WIN)
552         // GDI does not support character to glyph mapping outside BMP.
553         if (gSkFontMgr_DefaultFactory == &SkFontMgr_New_GDI &&
554             0xFFFF < originalCodepoints[i] && newCodepoints[i] == 0)
555         {
556             continue;
557         }
558 #endif
559         // If two codepoints map to the same glyph then this assert is not valid.
560         // However, the emoji test font should never have multiple characters map to the same glyph.
561         REPORTER_ASSERT(reporter, originalCodepoints[i] == newCodepoints[i],
562                         "name:%s i:%zu original:%d new:%d glyph:%d", familyName.c_str(), i,
563                         originalCodepoints[i], newCodepoints[i], glyphs[i]);
564     }
565 }
566 #endif
567 
568 // This test makes sure the legacy typeface creation does not lose its specified
569 // style. See https://bugs.chromium.org/p/skia/issues/detail?id=8447 for more
570 // context.
571 #ifdef SKIA_COMPILE_DM_ALL
DEF_TEST(LegacyMakeTypeface,reporter)572 DEF_TEST(LegacyMakeTypeface, reporter) {
573     sk_sp<SkFontMgr> fm = SkFontMgr::RefDefault();
574     sk_sp<SkTypeface> typeface1 = fm->legacyMakeTypeface(nullptr, SkFontStyle::Italic());
575     sk_sp<SkTypeface> typeface2 = fm->legacyMakeTypeface(nullptr, SkFontStyle::Bold());
576     sk_sp<SkTypeface> typeface3 = fm->legacyMakeTypeface(nullptr, SkFontStyle::BoldItalic());
577 
578     REPORTER_ASSERT(reporter, typeface1->isItalic());
579     REPORTER_ASSERT(reporter, !typeface1->isBold());
580     REPORTER_ASSERT(reporter, !typeface2->isItalic());
581     REPORTER_ASSERT(reporter, typeface2->isBold());
582     REPORTER_ASSERT(reporter, typeface3->isItalic());
583     REPORTER_ASSERT(reporter, typeface3->isBold());
584 }
585 #endif
586