| /* | |
| * Copyright 2023 Google LLC | |
| * | |
| * 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<SkTypeface> reportTypeface) { | |
| canvas->drawSimpleText(text.c_str(), | |
| text.size() - 1, | |
| SkTextEncoding::kUTF8, | |
| 0, | |
| 0, | |
| SkFont(reportTypeface, kDumpFontSize), | |
| SkPaint()); | |
| } | |
| void dumpLocalizedStrings(SkCanvas* canvas, | |
| sk_sp<SkTypeface> typeface, | |
| sk_sp<SkTypeface> 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<SkTypeface> typeface, | |
| sk_sp<SkTypeface> reportTypeface) { | |
| SkString glyphCount; | |
| glyphCount.printf("Num glyphs: %d\n", typeface->countGlyphs()); | |
| dumpToCanvas(canvas, glyphCount, reportTypeface); | |
| } | |
| void dumpFamilyAndPostscriptName(SkCanvas* canvas, | |
| sk_sp<SkTypeface> typeface, | |
| sk_sp<SkTypeface> 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<SkFontArguments::VariationPosition::Coordinate> | |
| specifiedVariations, | |
| TypefaceConstruction construction = TypefaceConstruction::kMakeWithFontArguments) | |
| : fTestName(testName) | |
| , fTestFontFilename(testFontFilename) | |
| , fConstruction(construction) { | |
| this->setBGColor(SK_ColorWHITE); | |
| fVariationPosition.coordinateCount = specifiedVariations.size(); | |
| fCoordinates = std::make_unique<SkFontArguments::VariationPosition::Coordinate[]>( | |
| 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<char32_t>::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<SkTypeface> fTestTypeface; | |
| sk_sp<SkTypeface> fReportTypeface; | |
| SkFontArguments::VariationPosition fVariationPosition; | |
| std::unique_ptr<SkFontArguments::VariationPosition::Coordinate[]> 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 |