Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Functions
TypefaceTest.cpp File Reference
#include "include/core/SkData.h"
#include "include/core/SkFont.h"
#include "include/core/SkFontArguments.h"
#include "include/core/SkFontMgr.h"
#include "include/core/SkFontParameters.h"
#include "include/core/SkFontStyle.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkStream.h"
#include "include/core/SkString.h"
#include "include/core/SkTypeface.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkFixed.h"
#include "include/private/base/SkTemplates.h"
#include "src/base/SkEndian.h"
#include "src/base/SkUTF.h"
#include "src/core/SkFontDescriptor.h"
#include "src/core/SkFontPriv.h"
#include "src/core/SkTypefaceCache.h"
#include "src/sfnt/SkOTTable_OS_2.h"
#include "src/sfnt/SkOTTable_OS_2_V0.h"
#include "src/sfnt/SkSFNTHeader.h"
#include "tests/Test.h"
#include "tools/Resources.h"
#include "tools/ToolUtils.h"
#include "tools/fonts/FontToolUtils.h"
#include "tools/fonts/TestEmptyTypeface.h"
#include <algorithm>
#include <array>
#include <cinttypes>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <memory>
#include <utility>

Go to the source code of this file.

Functions

static void TypefaceStyle_test (skiatest::Reporter *reporter, uint16_t weight, uint16_t width, SkData *data)
 
 DEF_TEST (TypefaceStyle, reporter)
 
 DEF_TEST (TypefaceStyleVariable, reporter)
 
 DEF_TEST (TypefacePostScriptName, reporter)
 
 DEF_TEST (TypefaceRoundTrip, reporter)
 
 DEF_TEST (FontDescriptorNegativeVariationSerialize, reporter)
 
 DEF_TEST (TypefaceAxes, reporter)
 
 DEF_TEST (TypefaceVariationIndex, reporter)
 
 DEF_TEST (Typeface, reporter)
 
 DEF_TEST (TypefaceAxesParameters, reporter)
 
static bool count_proc (SkTypeface *face, void *ctx)
 
static int count (skiatest::Reporter *reporter, const SkTypefaceCache &cache)
 
 DEF_TEST (TypefaceCache, reporter)
 
static void check_serialize_behaviors (sk_sp< SkTypeface > tf, skiatest::Reporter *reporter)
 
 DEF_TEST (Typeface_serialize, reporter)
 
 DEF_TEST (Typeface_glyph_to_char, reporter)
 
 DEF_TEST (LegacyMakeTypeface, reporter)
 

Function Documentation

◆ check_serialize_behaviors()

static void check_serialize_behaviors ( sk_sp< SkTypeface tf,
skiatest::Reporter reporter 
)
static

Definition at line 592 of file TypefaceTest.cpp.

592 {
593 if (!tf) {
594 return;
595 }
596
598 bool serialize;
599 tf->getFontDescriptor(&desc, &serialize);
600
604
605 REPORTER_ASSERT(reporter, data0->size() >= data1->size());
606
607 if (serialize) {
608 REPORTER_ASSERT(reporter, data0->equals(data2.get()));
609 } else {
610 REPORTER_ASSERT(reporter, data1->equals(data2.get()));
611 }
612}
reporter
#define REPORTER_ASSERT(r, cond,...)
Definition Test.h:286
void getFontDescriptor(SkFontDescriptor *desc, bool *isLocal) const
Definition SkTypeface.h:326
void serialize(SkWStream *, SerializeBehavior=SerializeBehavior::kIncludeDataIfLocal) const

◆ count()

static int count ( skiatest::Reporter reporter,
const SkTypefaceCache cache 
)
static

Definition at line 564 of file TypefaceTest.cpp.

564 {
565 int count = 0;
566 sk_sp<SkTypeface> none = cache.findByProcAndRef(count_proc, &count);
567 REPORTER_ASSERT(reporter, none == nullptr);
568 return count;
569}
int count
static bool count_proc(SkTypeface *face, void *ctx)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets Path to the Flutter assets directory enable service port Allow the VM service to fallback to automatic port selection if binding to a specified port fails trace Trace early application lifecycle Automatically switches to an endless trace buffer trace skia Filters out all Skia trace event categories except those that are specified in this comma separated list dump skp on shader Automatically dump the skp that triggers new shader compilations This is useful for writing custom ShaderWarmUp to reduce jank By this is not enabled to reduce the overhead purge persistent cache
Definition switches.h:191

◆ count_proc()

static bool count_proc ( SkTypeface face,
void *  ctx 
)
static

Definition at line 559 of file TypefaceTest.cpp.

559 {
560 int* count = static_cast<int*>(ctx);
561 *count = *count + 1;
562 return false;
563}

◆ DEF_TEST() [1/13]

DEF_TEST ( FontDescriptorNegativeVariationSerialize  ,
reporter   
)

Definition at line 213 of file TypefaceTest.cpp.

213 {
216 desc.setStyle(style);
217 const char postscriptName[] = "postscript";
218 desc.setPostscriptName(postscriptName);
219 SkFontArguments::VariationPosition::Coordinate* variation = desc.setVariationCoordinates(1);
220 variation[0] = { 0, -1.0f };
221
223 desc.serialize(&stream);
224 SkFontDescriptor descD;
225 SkFontDescriptor::Deserialize(stream.detachAsStream().get(), &descD);
226
227 REPORTER_ASSERT(reporter, descD.getStyle() == style);
228 REPORTER_ASSERT(reporter, 0 == strcmp(desc.getPostscriptName(), postscriptName));
229 if (descD.getVariationCoordinateCount() != 1) {
230 REPORT_FAILURE(reporter, "descD.getVariationCoordinateCount() != 1", SkString());
231 return;
232 }
233
234 REPORTER_ASSERT(reporter, descD.getVariation()[0].value == -1.0f);
235}
#define REPORT_FAILURE(reporter, cond, message)
Definition Test.h:90
SkFontStyle getStyle() const
const SkFontArguments::VariationPosition::Coordinate * getVariation() const
static bool Deserialize(SkStream *, SkFontDescriptor *result)
int getVariationCoordinateCount() const

◆ DEF_TEST() [2/13]

DEF_TEST ( LegacyMakeTypeface  ,
reporter   
)

Definition at line 663 of file TypefaceTest.cpp.

663 {
665 sk_sp<SkTypeface> typeface1 = fm->legacyMakeTypeface(nullptr, SkFontStyle::Italic());
666 sk_sp<SkTypeface> typeface2 = fm->legacyMakeTypeface(nullptr, SkFontStyle::Bold());
667 sk_sp<SkTypeface> typeface3 = fm->legacyMakeTypeface(nullptr, SkFontStyle::BoldItalic());
668
669 if (typeface1 || typeface2 || typeface3) {
670 REPORTER_ASSERT(reporter, typeface1 && typeface2 && typeface1);
671 }
672
673 if (typeface1) {
674 REPORTER_ASSERT(reporter, typeface1->isItalic());
675 REPORTER_ASSERT(reporter, !typeface1->isBold());
676 }
677 if (typeface2) {
678 REPORTER_ASSERT(reporter, !typeface2->isItalic());
679 REPORTER_ASSERT(reporter, typeface2->isBold());
680 }
681 if (typeface3) {
682 REPORTER_ASSERT(reporter, typeface3->isItalic());
683 REPORTER_ASSERT(reporter, typeface3->isBold());
684 }
685}
static constexpr SkFontStyle Italic()
Definition SkFontStyle.h:72
static constexpr SkFontStyle BoldItalic()
Definition SkFontStyle.h:75
static constexpr SkFontStyle Bold()
Definition SkFontStyle.h:69
sk_sp< SkFontMgr > TestFontMgr()

◆ DEF_TEST() [3/13]

DEF_TEST ( Typeface  ,
reporter   
)

Definition at line 406 of file TypefaceTest.cpp.

406 {
407
410
411 REPORTER_ASSERT(reporter, SkTypeface::Equal(t1.get(), t2.get()));
412 REPORTER_ASSERT(reporter, SkTypeface::Equal(nullptr, nullptr));
413
414 REPORTER_ASSERT(reporter, !SkTypeface::Equal(nullptr, t1.get()));
415 REPORTER_ASSERT(reporter, !SkTypeface::Equal(nullptr, t2.get()));
416 REPORTER_ASSERT(reporter, !SkTypeface::Equal(t1.get(), nullptr));
417 REPORTER_ASSERT(reporter, !SkTypeface::Equal(t2.get(), nullptr));
418}
static bool Equal(const SkTypeface *facea, const SkTypeface *faceb)
sk_sp< SkTypeface > DefaultTypeface()
sk_sp< SkTypeface > CreateTestTypeface(const char *name, SkFontStyle style)

◆ DEF_TEST() [4/13]

DEF_TEST ( Typeface_glyph_to_char  ,
reporter   
)

Definition at line 621 of file TypefaceTest.cpp.

621 {
623 SkFont font(emojiSample.typeface, 12);
624 SkASSERT(font.getTypeface());
625 char const * text = emojiSample.sampleText;
626 size_t const textLen = strlen(text);
627 SkString familyName;
628 font.getTypeface()->getFamilyName(&familyName);
629
630 size_t const codepointCount = SkUTF::CountUTF8(text, textLen);
631 char const * const textEnd = text + textLen;
632 std::unique_ptr<SkUnichar[]> originalCodepoints(new SkUnichar[codepointCount]);
633 for (size_t i = 0; i < codepointCount; ++i) {
634 originalCodepoints[i] = SkUTF::NextUTF8(&text, textEnd);
635 }
636 std::unique_ptr<SkGlyphID[]> glyphs(new SkGlyphID[codepointCount]);
637 font.unicharsToGlyphs(originalCodepoints.get(), codepointCount, glyphs.get());
638 if (std::any_of(glyphs.get(), glyphs.get()+codepointCount, [](SkGlyphID g){ return g == 0;})) {
639 ERRORF(reporter, "Unexpected typeface \"%s\". Expected full support for emoji_sample_text.",
640 familyName.c_str());
641 return;
642 }
643
644 std::unique_ptr<SkUnichar[]> newCodepoints(new SkUnichar[codepointCount]);
645 SkFontPriv::GlyphsToUnichars(font, glyphs.get(), codepointCount, newCodepoints.get());
646
647 for (size_t i = 0; i < codepointCount; ++i) {
648 // GDI does not support character to glyph mapping outside BMP.
649 if (ToolUtils::FontMgrIsGDI() && 0xFFFF < originalCodepoints[i] && newCodepoints[i] == 0) {
650 continue;
651 }
652 // If two codepoints map to the same glyph then this assert is not valid.
653 // However, the emoji test font should never have multiple characters map to the same glyph.
654 REPORTER_ASSERT(reporter, originalCodepoints[i] == newCodepoints[i],
655 "name:%s i:%zu original:%d new:%d glyph:%d", familyName.c_str(), i,
656 originalCodepoints[i], newCodepoints[i], glyphs[i]);
657 }
658}
uint16_t glyphs[5]
#define SkASSERT(cond)
Definition SkAssert.h:116
int32_t SkUnichar
Definition SkTypes.h:175
uint16_t SkGlyphID
Definition SkTypes.h:179
#define ERRORF(r,...)
Definition Test.h:293
static void GlyphsToUnichars(const SkFont &, const uint16_t glyphs[], int count, SkUnichar[])
Definition SkFont.cpp:396
const char * c_str() const
Definition SkString.h:133
std::u16string text
SK_SPI SkUnichar NextUTF8(const char **ptr, const char *end)
Definition SkUTF.cpp:118
SK_SPI int CountUTF8(const char *utf8, size_t byteLength)
Definition SkUTF.cpp:47
bool FontMgrIsGDI()
EmojiTestSample EmojiSample()
font
Font Metadata and Metrics.
sk_sp< SkTypeface > typeface

◆ DEF_TEST() [5/13]

DEF_TEST ( Typeface_serialize  ,
reporter   
)

Definition at line 614 of file TypefaceTest.cpp.

614 {
617 ToolUtils::TestFontMgr()->makeFromStream(GetResourceAsStream("fonts/Distortable.ttf")),
618 reporter);
619}
std::unique_ptr< SkStreamAsset > GetResourceAsStream(const char *resource, bool useFileStream)
Definition Resources.cpp:31
static void check_serialize_behaviors(sk_sp< SkTypeface > tf, skiatest::Reporter *reporter)

◆ DEF_TEST() [6/13]

DEF_TEST ( TypefaceAxes  ,
reporter   
)

Definition at line 237 of file TypefaceTest.cpp.

237 {
238 using Variation = SkFontArguments::VariationPosition;
239 // In DWrite in at least up to 1901 18363.1198 IDWriteFontFace5::GetFontAxisValues and
240 // GetFontAxisValueCount along with IDWriteFontResource::GetFontAxisAttributes and
241 // GetFontAxisCount (and related) seem to incorrectly collapse multiple axes with the same tag.
242 // Since this is a limitation of the underlying implementation, for now allow the test to pass
243 // with the axis tag count (as opposed to the axis count). Eventually all implementations should
244 // pass this test without 'alsoAcceptedAxisTagCount'.
245 auto test = [&](SkTypeface* typeface, const Variation& expected, int alsoAcceptedAxisTagCount) {
246 if (!typeface) {
247 return; // Not all SkFontMgr can makeFromStream().
248 }
249
250 int actualCount = typeface->getVariationDesignPosition(nullptr, 0);
251 if (actualCount == -1) {
252 return; // The number of axes is unknown.
253 }
254 REPORTER_ASSERT(reporter, actualCount == expected.coordinateCount ||
255 actualCount == alsoAcceptedAxisTagCount);
256
257 // Variable font conservative bounds don't vary, so ensure they aren't reported.
259
260 std::unique_ptr<Variation::Coordinate[]> actual(new Variation::Coordinate[actualCount]);
261 actualCount = typeface->getVariationDesignPosition(actual.get(), actualCount);
262 if (actualCount == -1) {
263 return; // The position cannot be determined.
264 }
265 REPORTER_ASSERT(reporter, actualCount == expected.coordinateCount ||
266 actualCount == alsoAcceptedAxisTagCount);
267
268 // Every actual must be expected.
269 std::unique_ptr<bool[]> expectedUsed(new bool[expected.coordinateCount]());
270 for (int actualIdx = 0; actualIdx < actualCount; ++actualIdx) {
271 bool actualFound = false;
272 for (int expectedIdx = 0; expectedIdx < expected.coordinateCount; ++expectedIdx) {
273 if (expectedUsed[expectedIdx]) {
274 continue;
275 }
276
277 if (actual[actualIdx].axis != expected.coordinates[expectedIdx].axis) {
278 continue;
279 }
280
281 // Convert to fixed for "almost equal".
282 SkFixed fixedRead = SkScalarToFixed(actual[actualIdx].value);
283 SkFixed fixedOriginal = SkScalarToFixed(expected.coordinates[expectedIdx].value);
284 if (!(SkTAbs(fixedRead - fixedOriginal) < 2)) {
285 continue;
286 }
287
288 // This actual matched an unused expected.
289 actualFound = true;
290 expectedUsed[expectedIdx] = true;
291 break;
292 }
293 REPORTER_ASSERT(reporter, actualFound,
294 "Actual axis '%c%c%c%c' with value '%f' not expected",
295 (char)((actual[actualIdx].axis >> 24) & 0xFF),
296 (char)((actual[actualIdx].axis >> 16) & 0xFF),
297 (char)((actual[actualIdx].axis >> 8) & 0xFF),
298 (char)((actual[actualIdx].axis ) & 0xFF),
299 SkScalarToDouble(actual[actualIdx].value));
300 }
301 };
302
304
305 // Not specifying a position should produce the default.
306 {
307 std::unique_ptr<SkStreamAsset> variable(GetResourceAsStream("fonts/Variable.ttf"));
308 if (!variable) {
309 REPORT_FAILURE(reporter, "variable", SkString());
310 return;
311 }
312 const Variation::Coordinate defaultPosition[] = {
313 { SkSetFourByteTag('w','g','h','t'), 400.0f },
314 { SkSetFourByteTag('w','d','t','h'), 100.0f },
315 };
316 sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(variable), 0);
317 test(typeface.get(), Variation{&defaultPosition[0], 2}, -1);
318 }
319
320 // Multiple axes with the same tag (and min, max, default) works.
321 {
322 std::unique_ptr<SkStreamAsset> dupTags(GetResourceAsStream("fonts/VaryAlongQuads.ttf"));
323 if (!dupTags) {
324 REPORT_FAILURE(reporter, "dupTags", SkString());
325 return;
326 }
327
328 // The position may be over specified. If there are multiple values for a given axis,
329 // ensure the last one since that's what css-fonts-4 requires.
330 const Variation::Coordinate position[] = {
331 { SkSetFourByteTag('w','g','h','t'), 700.0f },
332 { SkSetFourByteTag('w','g','h','t'), 600.0f },
333 { SkSetFourByteTag('w','g','h','t'), 600.0f },
334 };
336 params.setVariationDesignPosition({position, std::size(position)});
337 sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(dupTags), params);
338 test(typeface.get(), Variation{&position[1], 2}, 1);
339 }
340
341 // Overspecifying an axis tag value applies the last one in the list.
342 {
343 std::unique_ptr<SkStreamAsset> distortable(GetResourceAsStream("fonts/Distortable.ttf"));
344 if (!distortable) {
345 REPORT_FAILURE(reporter, "distortable", SkString());
346 return;
347 }
348
349 // The position may be over specified. If there are multiple values for a given axis,
350 // ensure the last one since that's what css-fonts-4 requires.
351 const Variation::Coordinate position[] = {
352 { SkSetFourByteTag('w','g','h','t'), 1.618033988749895f },
353 { SkSetFourByteTag('w','g','h','t'), SK_ScalarSqrt2 },
354 };
356 params.setVariationDesignPosition({position, std::size(position)});
357 sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(distortable), params);
358 test(typeface.get(), Variation{&position[1], 1}, -1);
359
360 if (typeface) {
361 // Cloning without specifying any parameters should produce an equivalent variation.
362 sk_sp<SkTypeface> clone = typeface->makeClone(SkFontArguments());
363 test(clone.get(), Variation{&position[1], 1}, -1);
364 }
365 }
366}
#define test(name)
int32_t SkFixed
Definition SkFixed.h:25
#define SkScalarToFixed(x)
Definition SkFixed.h:125
#define SkScalarToDouble(x)
Definition SkScalar.h:63
#define SK_ScalarSqrt2
Definition SkScalar.h:20
static T SkTAbs(T value)
Definition SkTemplates.h:43
static constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d)
Definition SkTypes.h:167
SkRect getBounds() const
int getVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
T * get() const
Definition SkRefCnt.h:303
const EmbeddedViewParams * params
SkFontArguments & setVariationDesignPosition(VariationPosition position)
bool isEmpty() const
Definition SkRect.h:693

◆ DEF_TEST() [7/13]

DEF_TEST ( TypefaceAxesParameters  ,
reporter   
)

Definition at line 420 of file TypefaceTest.cpp.

420 {
422
423 // In DWrite in at least up to 1901 18363.1198 IDWriteFontFace5::GetFontAxisValues and
424 // GetFontAxisValueCount along with IDWriteFontResource::GetFontAxisAttributes and
425 // GetFontAxisCount (and related) seem to incorrectly collapse multiple axes with the same tag.
426 // Since this is a limitation of the underlying implementation, for now allow the test to pass
427 // with the axis tag count (as opposed to the axis count). Eventually all implementations should
428 // pass this test without 'alsoAcceptedAxisTagCount'.
429 auto test = [&](SkTypeface* typeface, const Axis* expected, int expectedCount,
430 int alsoAcceptedAxisTagCount)
431 {
432 if (!typeface) {
433 return; // Not all SkFontMgr can makeFromStream().
434 }
435
436 int actualCount = typeface->getVariationDesignParameters(nullptr, 0);
437 if (actualCount == -1) {
438 return; // The number of axes is unknown.
439 }
440 REPORTER_ASSERT(reporter, actualCount == expectedCount ||
441 actualCount == alsoAcceptedAxisTagCount);
442
443 std::unique_ptr<Axis[]> actual(new Axis[actualCount]);
444 actualCount = typeface->getVariationDesignParameters(actual.get(), actualCount);
445 if (actualCount == -1) {
446 return; // The position cannot be determined.
447 }
448 REPORTER_ASSERT(reporter, actualCount == expectedCount ||
449 actualCount == alsoAcceptedAxisTagCount);
450
451 // Every actual must be expected.
452 std::unique_ptr<bool[]> expectedUsed(new bool[expectedCount]());
453 for (int actualIdx = 0; actualIdx < actualCount; ++actualIdx) {
454 bool actualFound = false;
455 for (int expectedIdx = 0; expectedIdx < expectedCount; ++expectedIdx) {
456 if (expectedUsed[expectedIdx]) {
457 continue;
458 }
459
460 if (actual[actualIdx].tag != expected[expectedIdx].tag) {
461 continue;
462 }
463
464 // Convert to fixed for "almost equal".
465 SkFixed fixedActualMin = SkScalarToFixed(actual[actualIdx].min);
466 SkFixed fixedExpectedMin = SkScalarToFixed(expected[expectedIdx].min);
467 if (!(SkTAbs(fixedActualMin - fixedExpectedMin) < 2)) {
468 continue;
469 }
470
471 SkFixed fixedActualMax = SkScalarToFixed(actual[actualIdx].max);
472 SkFixed fixedExpectedMax = SkScalarToFixed(expected[expectedIdx].max);
473 if (!(SkTAbs(fixedActualMax - fixedExpectedMax) < 2)) {
474 continue;
475 }
476
477 SkFixed fixedActualDefault = SkScalarToFixed(actual[actualIdx].def);
478 SkFixed fixedExpectedDefault = SkScalarToFixed(expected[expectedIdx].def);
479 if (!(SkTAbs(fixedActualDefault - fixedExpectedDefault) < 2)) {
480 continue;
481 }
482
483 // This seems silly, but allows MSAN to ensure that isHidden is initialized.
484 // In GDI or before macOS 10.12, Win10, or FreeType 2.8.1 API for hidden is missing.
485 if (actual[actualIdx].isHidden() &&
486 actual[actualIdx].isHidden() != expected[expectedIdx].isHidden())
487 {
488 continue;
489 }
490
491 // This actual matched an unused expected.
492 actualFound = true;
493 expectedUsed[expectedIdx] = true;
494 break;
495 }
496 REPORTER_ASSERT(reporter, actualFound,
497 "Actual axis '%c%c%c%c' with min %f max %f default %f hidden %s not expected",
498 (char)((actual[actualIdx].tag >> 24) & 0xFF),
499 (char)((actual[actualIdx].tag >> 16) & 0xFF),
500 (char)((actual[actualIdx].tag >> 8) & 0xFF),
501 (char)((actual[actualIdx].tag ) & 0xFF),
502 actual[actualIdx].min,
503 actual[actualIdx].def,
504 actual[actualIdx].max,
505 actual[actualIdx].isHidden() ? "true" : "false");
506 }
507 };
508
510
511 // Two axis OpenType variable font.
512 {
513 std::unique_ptr<SkStreamAsset> variable(GetResourceAsStream("fonts/Variable.ttf"));
514 if (!variable) {
515 REPORT_FAILURE(reporter, "variable", SkString());
516 return;
517 }
518 constexpr Axis expected[] = {
519 Axis(SkSetFourByteTag('w','g','h','t'), 100.0f, 400.0f, 900.0f, true ),
520 Axis(SkSetFourByteTag('w','d','t','h'), 50.0f, 100.0f, 200.0f, false),
521 };
522 sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(variable), 0);
523 test(typeface.get(), &expected[0], std::size(expected), -1);
524 }
525
526 // Multiple axes with the same tag (and min, max, default) works.
527 {
528 std::unique_ptr<SkStreamAsset> dupTags(GetResourceAsStream("fonts/VaryAlongQuads.ttf"));
529 if (!dupTags) {
530 REPORT_FAILURE(reporter, "dupTags", SkString());
531 return;
532 }
533
534 // The position may be over specified. If there are multiple values for a given axis,
535 // ensure the last one since that's what css-fonts-4 requires.
536 constexpr Axis expected[] = {
537 Axis(SkSetFourByteTag('w','g','h','t'), 100.0f, 400.0f, 900.0f, false),
538 Axis(SkSetFourByteTag('w','g','h','t'), 100.0f, 400.0f, 900.0f, false),
539 };
540 sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(dupTags), 0);
541 test(typeface.get(), &expected[0], std::size(expected), 1);
542 }
543
544 // Simple single axis GX variable font.
545 {
546 std::unique_ptr<SkStreamAsset> distortable(GetResourceAsStream("fonts/Distortable.ttf"));
547 if (!distortable) {
548 REPORT_FAILURE(reporter, "distortable", SkString());
549 return;
550 }
551 constexpr Axis expected[] = {
552 Axis(SkSetFourByteTag('w','g','h','t'), 0.5f, 1.0f, 2.0f, true),
553 };
554 sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(distortable), 0);
555 test(typeface.get(), &expected[0], std::size(expected), -1);
556 }
557}
int getVariationDesignParameters(SkFontParameters::Variation::Axis parameters[], int parameterCount) const
static float max(float r, float g, float b)
Definition hsl.cpp:49
static float min(float r, float g, float b)
Definition hsl.cpp:48

◆ DEF_TEST() [8/13]

DEF_TEST ( TypefaceCache  ,
reporter   
)

Definition at line 571 of file TypefaceTest.cpp.

571 {
573 {
575 REPORTER_ASSERT(reporter, count(reporter, cache) == 0);
576 {
578 cache.add(t0);
579 REPORTER_ASSERT(reporter, count(reporter, cache) == 1);
580 cache.add(t1);
581 REPORTER_ASSERT(reporter, count(reporter, cache) == 2);
582 cache.purgeAll();
583 REPORTER_ASSERT(reporter, count(reporter, cache) == 2);
584 }
585 REPORTER_ASSERT(reporter, count(reporter, cache) == 2);
586 cache.purgeAll();
587 REPORTER_ASSERT(reporter, count(reporter, cache) == 1);
588 }
589 REPORTER_ASSERT(reporter, t1->unique());
590}
static sk_sp< SkTypeface > Make()

◆ DEF_TEST() [9/13]

DEF_TEST ( TypefacePostScriptName  ,
reporter   
)

Definition at line 182 of file TypefaceTest.cpp.

182 {
184 if (!typeface) {
185 // Not all SkFontMgr can MakeFromStream().
186 return;
187 }
188
189 SkString postScriptName;
190 bool hasName = typeface->getPostScriptName(&postScriptName);
191 bool hasName2 = typeface->getPostScriptName(nullptr);
192 REPORTER_ASSERT(reporter, hasName == hasName2);
193 if (hasName) {
194 REPORTER_ASSERT(reporter, postScriptName == SkString("Em"));
195 }
196}
sk_sp< SkTypeface > CreateTypefaceFromResource(const char *resource, int ttcIndex)

◆ DEF_TEST() [10/13]

DEF_TEST ( TypefaceRoundTrip  ,
reporter   
)

Definition at line 198 of file TypefaceTest.cpp.

198 {
200 if (!typeface) {
201 // Not all SkFontMgr can MakeFromStream().
202 return;
203 }
204
205 int fontIndex;
206 std::unique_ptr<SkStreamAsset> stream = typeface->openStream(&fontIndex);
207
208 sk_sp<SkTypeface> typeface2 =
209 ToolUtils::TestFontMgr()->makeFromStream(std::move(stream), fontIndex);
210 REPORTER_ASSERT(reporter, typeface2);
211}
sk_sp< SkTypeface > makeFromStream(std::unique_ptr< SkStreamAsset >, int ttcIndex=0) const

◆ DEF_TEST() [11/13]

DEF_TEST ( TypefaceStyle  ,
reporter   
)

Definition at line 103 of file TypefaceTest.cpp.

103 {
104 std::unique_ptr<SkStreamAsset> stream(GetResourceAsStream("fonts/Em.ttf"));
105 if (!stream) {
106 REPORT_FAILURE(reporter, "fonts/Em.ttf", SkString("Cannot load resource"));
107 return;
108 }
110
111 using SkFS = SkFontStyle;
112 for (int weight = SkFS::kInvisible_Weight; weight <= SkFS::kExtraBlack_Weight; ++weight) {
113 TypefaceStyle_test(reporter, weight, 5, data.get());
114 }
115 for (int width = SkFS::kUltraCondensed_Width; width <= SkFS::kUltraExpanded_Width; ++width) {
117 }
118}
static void TypefaceStyle_test(skiatest::Reporter *reporter, uint16_t weight, uint16_t width, SkData *data)
static sk_sp< SkData > MakeFromStream(SkStream *, size_t size)
Definition SkData.cpp:208
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41
int32_t width

◆ DEF_TEST() [12/13]

DEF_TEST ( TypefaceStyleVariable  ,
reporter   
)

Definition at line 120 of file TypefaceTest.cpp.

120 {
121 using Variation = SkFontArguments::VariationPosition;
123
124 std::unique_ptr<SkStreamAsset> stream(GetResourceAsStream("fonts/Variable.ttf"));
125 if (!stream) {
126 REPORT_FAILURE(reporter, "fonts/Variable.ttf", SkString("Cannot load resource"));
127 return;
128 }
129 sk_sp<SkTypeface> typeface(ToolUtils::TestFontMgr()->makeFromStream(stream->duplicate()));
130 if (!typeface) {
131 // Not all SkFontMgr can MakeFromStream().
132 return;
133 }
134
135 // Creating Variable.ttf without any extra parameters should have a normal font style.
136 SkFontStyle fs = typeface->fontStyle();
138 "fs: %d %d %d", fs.weight(), fs.width(), fs.slant());
139
140 // Ensure that the font supports variable stuff
141 Variation::Coordinate varPos[2];
142 int numAxes = typeface->getVariationDesignPosition(varPos, std::size(varPos));
143 if (numAxes <= 0) {
144 // Not all SkTypeface can get the variation.
145 return;
146 }
147 if (numAxes != 2) {
148 // Variable.ttf has two axes.
149 REPORTER_ASSERT(reporter, numAxes == 2);
150 return;
151 }
152
153 // If a fontmgr or typeface can do variations, ensure the variation affects the reported style.
154 const Variation::Coordinate nonDefaultPosition[] = {
155 { SkSetFourByteTag('w','g','h','t'), 200.0f },
156 { SkSetFourByteTag('w','d','t','h'), 75.0f },
157 };
158 const SkFontStyle expectedStyle(200, 3, SkFontStyle::kUpright_Slant);
159
160 // On Mac10.15 and earlier, the wdth affected the style using the old gx ranges.
161 // On macOS 11 and later, the wdth affects the style using the new OpenType ranges.
162 // Allow old CoreText to report the wrong width values.
163#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
164 SkFontStyle mac1015style(200, 9, SkFontStyle::kUpright_Slant);
165#else
166 SkFontStyle mac1015style = expectedStyle;
167#endif
169 args.setVariationDesignPosition(Variation{nonDefaultPosition, std::size(nonDefaultPosition)});
170
171 sk_sp<SkTypeface> nonDefaultTypeface = fm->makeFromStream(stream->duplicate(), args);
172 SkFontStyle ndfs = nonDefaultTypeface->fontStyle();
173 REPORTER_ASSERT(reporter, ndfs == expectedStyle || ndfs == mac1015style,
174 "ndfs: %d %d %d", ndfs.weight(), ndfs.width(), ndfs.slant());
175
176 sk_sp<SkTypeface> cloneTypeface = typeface->makeClone(args);
177 SkFontStyle cfs = cloneTypeface->fontStyle();
178 REPORTER_ASSERT(reporter, cfs == expectedStyle || cfs == mac1015style,
179 "cfs: %d %d %d", cfs.weight(), cfs.width(), cfs.slant());
180}
Slant slant() const
Definition SkFontStyle.h:64
int width() const
Definition SkFontStyle.h:63
int weight() const
Definition SkFontStyle.h:62
static constexpr SkFontStyle Normal()
Definition SkFontStyle.h:66
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args

◆ DEF_TEST() [13/13]

DEF_TEST ( TypefaceVariationIndex  ,
reporter   
)

Definition at line 368 of file TypefaceTest.cpp.

368 {
369 std::unique_ptr<SkStreamAsset> distortable(GetResourceAsStream("fonts/Distortable.ttf"));
370 if (!distortable) {
371 REPORT_FAILURE(reporter, "distortable", SkString());
372 return;
373 }
374
377 // The first named variation position in Distortable is 'Thin'.
378 params.setCollectionIndex(0x00010000);
379 sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(distortable), params);
380 if (!typeface) {
381 // FreeType is the only weird thing that supports this, Skia just needs to make sure if it
382 // gets one of these things make sense.
383 return;
384 }
385
386 int count = typeface->getVariationDesignPosition(nullptr, 0);
387 if (!(count == 1)) {
388 REPORT_FAILURE(reporter, "count == 1", SkString());
389 return;
390 }
391
393 count = typeface->getVariationDesignPosition(positionRead, std::size(positionRead));
394 if (count == -1) {
395 return;
396 }
397 if (!(count == 1)) {
398 REPORT_FAILURE(reporter, "count == 1", SkString());
399 return;
400 }
401 REPORTER_ASSERT(reporter, positionRead[0].axis == SkSetFourByteTag('w','g','h','t'));
402 REPORTER_ASSERT(reporter, positionRead[0].value == 0.5,
403 "positionRead[0].value: %f", positionRead[0].value);
404}
SkFontArguments & setCollectionIndex(int collectionIndex)

◆ TypefaceStyle_test()

static void TypefaceStyle_test ( skiatest::Reporter reporter,
uint16_t  weight,
uint16_t  width,
SkData data 
)
static

Definition at line 46 of file TypefaceTest.cpp.

48{
49 sk_sp<SkData> dataCopy;
50 if (!data->unique()) {
51 dataCopy = SkData::MakeWithCopy(data->data(), data->size());
52 data = dataCopy.get();
53 }
54 SkSFNTHeader* sfntHeader = static_cast<SkSFNTHeader*>(data->writable_data());
55
57 SkTAfter<SkSFNTHeader::TableDirectoryEntry>(sfntHeader);
58 SkSFNTHeader::TableDirectoryEntry* os2TableEntry = nullptr;
59 int numTables = SkEndian_SwapBE16(sfntHeader->numTables);
60 for (int tableEntryIndex = 0; tableEntryIndex < numTables; ++tableEntryIndex) {
61 if (SkOTTableOS2::TAG == tableEntry[tableEntryIndex].tag) {
62 os2TableEntry = tableEntry + tableEntryIndex;
63 break;
64 }
65 }
66 SkASSERT_RELEASE(os2TableEntry);
67
68 size_t os2TableOffset = SkEndian_SwapBE32(os2TableEntry->offset);
69 SkOTTableOS2_V0* os2Table = SkTAddOffset<SkOTTableOS2_V0>(sfntHeader, os2TableOffset);
70 os2Table->usWeightClass.value = SkEndian_SwapBE16(weight);
71 using WidthType = SkOTTableOS2_V0::WidthClass::Value;
72 os2Table->usWidthClass.value = static_cast<WidthType>(SkEndian_SwapBE16(width));
73
74 sk_sp<SkTypeface> newTypeface(ToolUtils::TestFontMgr()->makeFromData(sk_ref_sp(data)));
75 if (!newTypeface) {
76 // Not all SkFontMgr can MakeFromStream().
77 return;
78 }
79
80 SkFontStyle newStyle = newTypeface->fontStyle();
81
82 //printf("%d, %f\n", weight, (newStyle.weight() - (float)0x7FFF) / (float)0x7FFF);
83 //printf("%d, %f\n", width , (newStyle.width() - (float)0x7F) / (float)0x7F);
84 //printf("%d, %d\n", weight, newStyle.weight());
85 //printf("%d, %d\n", width , newStyle.width());
86
87 // Some back-ends (CG, GDI, DW) support OS/2 version A which uses 0 - 10 (but all differently).
89 newStyle.weight() == weight ||
90 (weight <= 10 && newStyle.weight() == 100 * weight) ||
91 (weight == 4 && newStyle.weight() == 350) || // GDI weirdness
92 (weight == 5 && newStyle.weight() == 400) || // GDI weirdness
93 (weight == 0 && newStyle.weight() == 1) || // DW weirdness
94 (weight == 1000 && newStyle.weight() == 999) // DW weirdness
95 );
96
97 // Some back-ends (GDI) don't support width, ensure these always report 'normal'.
100 newStyle.width() == width || newStyle.width() == SkFontStyle::Width::kNormal_Width,
101 "newStyle.width(): %d width: %" PRIu16, newStyle.width(), width);
102}
#define SkASSERT_RELEASE(cond)
Definition SkAssert.h:100
#define SkEndian_SwapBE32(n)
Definition SkEndian.h:136
#define SkEndian_SwapBE16(n)
Definition SkEndian.h:135
sk_sp< T > sk_ref_sp(T *obj)
Definition SkRefCnt.h:381
static sk_sp< SkData > MakeWithCopy(const void *data, size_t length)
Definition SkData.cpp:111
enum SkOTTableOS2_V0::WidthClass::Value value
struct SkOTTableOS2_V0::WidthClass usWidthClass
struct SkOTTableOS2_V0::WeightClass usWeightClass
static constexpr SK_OT_ULONG TAG
SK_SFNT_USHORT numTables