/* * Copyright 2023 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "gm/gm.h" #include "include/core/SkCanvas.h" #include "include/core/SkFont.h" #include "include/core/SkRefCnt.h" #include "include/core/SkStream.h" #include "include/core/SkString.h" #include "include/core/SkTypeface.h" #include "include/ports/SkTypeface_fontations.h" #include "tools/Resources.h" namespace skiagm { namespace { const SkScalar kTextSizes[] = {12, 18, 30, 120}; const char kReportFontName[] = "fonts/Roboto-Regular.ttf"; const SkScalar kDumpFontSize = 20.0f; // TODO(drott): Test these dumps is in a unit test instead of dumping them to GM surface. void dumpToCanvas(SkCanvas* canvas, SkString text, sk_sp reportTypeface) { canvas->drawSimpleText(text.c_str(), text.size() - 1, SkTextEncoding::kUTF8, 0, 0, SkFont(reportTypeface, kDumpFontSize), SkPaint()); } void dumpLocalizedStrings(SkCanvas* canvas, sk_sp typeface, sk_sp reportTypeface) { auto family_names = typeface->createFamilyNameIterator(); SkTypeface::LocalizedString famName; SkString localizedName; while (family_names->next(&famName)) { localizedName.printf( "Name: %s Language: %s\n", famName.fString.c_str(), famName.fLanguage.c_str()); dumpToCanvas(canvas, localizedName, reportTypeface); canvas->translate(0, kDumpFontSize * 1.2); } family_names->unref(); } void dumpGlyphCount(SkCanvas* canvas, sk_sp typeface, sk_sp reportTypeface) { SkString glyphCount; glyphCount.printf("Num glyphs: %d\n", typeface->countGlyphs()); dumpToCanvas(canvas, glyphCount, reportTypeface); } void dumpFamilyAndPostscriptName(SkCanvas* canvas, sk_sp typeface, sk_sp reportTypeface) { SkString name; typeface->getFamilyName(&name); SkString nameDump; nameDump.printf("Family name: %s\n", name.c_str()); dumpToCanvas(canvas, nameDump, reportTypeface); if (typeface->getPostScriptName(&name)) { canvas->translate(0, kDumpFontSize * 1.2); nameDump.printf("PS Name: %s\n", name.c_str()); dumpToCanvas(canvas, nameDump, reportTypeface); } else { canvas->translate(0, kDumpFontSize * 1.2); nameDump.printf("No Postscript name."); dumpToCanvas(canvas, nameDump, reportTypeface); } } } // namespace class FontationsTypefaceGM : public GM { public: enum class TypefaceConstruction { kMakeWithFontArguments, kCloneWithFontArguments, }; FontationsTypefaceGM(const char* testName, const char* testFontFilename, std::initializer_list specifiedVariations, TypefaceConstruction construction = TypefaceConstruction::kMakeWithFontArguments) : fTestName(testName) , fTestFontFilename(testFontFilename) , fConstruction(construction) { this->setBGColor(SK_ColorWHITE); fVariationPosition.coordinateCount = specifiedVariations.size(); fCoordinates = std::make_unique( specifiedVariations.size()); for (size_t i = 0; i < specifiedVariations.size(); ++i) { fCoordinates[i] = std::data(specifiedVariations)[i]; } fVariationPosition.coordinates = fCoordinates.get(); } protected: void onOnceBeforeDraw() override { if (fConstruction == TypefaceConstruction::kMakeWithFontArguments) { fTestTypeface = SkTypeface_Make_Fontations( GetResourceAsStream(fTestFontFilename), SkFontArguments().setVariationDesignPosition(fVariationPosition)); } else { fTestTypeface = SkTypeface_Make_Fontations(GetResourceAsStream(fTestFontFilename), SkFontArguments()) ->makeClone(SkFontArguments().setVariationDesignPosition( fVariationPosition)); } fReportTypeface = SkTypeface_Make_Fontations(GetResourceAsStream(kReportFontName), SkFontArguments()); } SkString getName() const override { return SkStringPrintf("typeface_fontations_%s", fTestName.c_str()); } SkISize getISize() override { return SkISize::Make(400, 200); } DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override { SkPaint paint; paint.setColor(SK_ColorBLACK); if (!fTestTypeface) { *errorMsg = "Unable to initialize typeface."; return DrawResult::kSkip; } SkFont font(fTestTypeface); const char32_t testText[] = U"abc"; size_t testTextBytesize = std::char_traits::length(testText) * sizeof(char32_t); SkScalar x = 100; SkScalar y = 150; for (SkScalar textSize : kTextSizes) { font.setSize(textSize); y += font.getSpacing(); /* Draw origin marker as a green dot. */ paint.setColor(SK_ColorGREEN); canvas->drawRect(SkRect::MakeXYWH(x, y, 2, 2), paint); paint.setColor(SK_ColorBLACK); canvas->drawSimpleText( testText, testTextBytesize, SkTextEncoding::kUTF32, x, y, font, paint); } canvas->translate(100, 470); dumpGlyphCount(canvas, fTestTypeface, fReportTypeface); canvas->translate(0, kDumpFontSize * 1.2); dumpLocalizedStrings(canvas, fTestTypeface, fReportTypeface); canvas->translate(0, kDumpFontSize * 1.2); dumpFamilyAndPostscriptName(canvas, fTestTypeface, fReportTypeface); return DrawResult::kOk; } private: using INHERITED = GM; const SkString fTestName; const char* fTestFontFilename; sk_sp fTestTypeface; sk_sp fReportTypeface; SkFontArguments::VariationPosition fVariationPosition; std::unique_ptr fCoordinates; TypefaceConstruction fConstruction; }; namespace { SkFourByteTag constexpr operator"" _t(const char* tagName, size_t size) { SkASSERT(size == 4); return SkSetFourByteTag(tagName[0], tagName[1], tagName[2], tagName[3]); } } // namespace DEF_GM(return new FontationsTypefaceGM("roboto", "fonts/Roboto-Regular.ttf", {});) DEF_GM(return new FontationsTypefaceGM( "distortable_light", "fonts/Distortable.ttf", {{"wght"_t, 0.5f}})) DEF_GM(return new FontationsTypefaceGM( "distortable_bold", "fonts/Distortable.ttf", {{"wght"_t, 2.0f}}, FontationsTypefaceGM::TypefaceConstruction::kCloneWithFontArguments);) } // namespace skiagm