/* * Copyright 2015 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/SkFontArguments.h" #include "include/core/SkFontMgr.h" #include "include/core/SkFontTypes.h" #include "include/core/SkPaint.h" #include "include/core/SkRect.h" #include "include/core/SkRefCnt.h" #include "include/core/SkScalar.h" #include "include/core/SkSize.h" #include "include/core/SkStream.h" #include "include/core/SkString.h" #include "include/core/SkTypeface.h" #include "include/core/SkTypes.h" #include "tools/Resources.h" #include "tools/SkMetaData.h" #include #include #include namespace skiagm { class FontScalerDistortableGM : public GM { public: FontScalerDistortableGM() { this->setBGColor(0xFFFFFFFF); } private: SkString onShortName() override { return SkString("fontscalerdistortable"); } SkISize onISize() override { return SkISize::Make(550, 700); } bool fDirty = true; bool fOverride = false; size_t fAxisSliderCount = 0; struct AxisSlider { SkFourByteTag axis; SkScalar control[3]; SkString name; }; std::unique_ptr fAxisSliders; bool onGetControls(SkMetaData* controls) override { controls->setBool("Override", fOverride); for (size_t i = 0; i < fAxisSliderCount; ++i) { controls->setScalars(fAxisSliders[i].name.c_str(), 3, fAxisSliders[i].control); } return true; } void onSetControls(const SkMetaData& controls) override { bool oldOverride = fOverride; controls.findBool("Override", &fOverride); if (fOverride != oldOverride) { fDirty = true; } for (size_t i = 0; i < fAxisSliderCount; ++i) { SkScalar oldValue = fAxisSliders[i].control[0]; controls.findScalars(fAxisSliders[i].name.c_str(), nullptr, fAxisSliders[i].control); if (oldValue != fAxisSliders[i].control[0]) { fDirty = true; } } } struct Info { sk_sp distortable; SkFourByteTag axisTag; SkScalar axisMin; SkScalar axisMax; } fInfo; void onOnceBeforeDraw() override { constexpr SkFourByteTag wght = SkSetFourByteTag('w','g','h','t'); //constexpr SkFourByteTag wdth = SkSetFourByteTag('w','d','t','h'); fInfo = { MakeResourceAsTypeface("fonts/Distortable.ttf"), wght, 0.5f, 2.0f //SkTypeface::MakeFromFile("/Library/Fonts/Skia.ttf"), wght, 0.48f, 3.2f //SkTypeface::MakeFromName("Skia", SkFontStyle()), wdth, 0.62f, 1.3f //SkTypeface::MakeFromFile("/System/Library/Fonts/SFNS.ttf"), wght, 100.0f, 900.0f //SkTypeface::MakeFromName(".SF NS", SkFontStyle()), wght, 100.0f, 900.0f }; if (fInfo.distortable) { int axisCount = fInfo.distortable->getVariationDesignParameters(nullptr, 0); if (axisCount > 0) { auto axes = std::make_unique(axisCount); axisCount = fInfo.distortable->getVariationDesignParameters(axes.get(), axisCount); if (axisCount > 0) { fAxisSliders = std::make_unique(axisCount); for (int i = 0; i < axisCount; ++i) { fAxisSliders[i].axis = axes[i].tag; fAxisSliders[i].control[0] = axes[i].def; fAxisSliders[i].control[1] = axes[i].min; fAxisSliders[i].control[2] = axes[i].max; fAxisSliders[i].name.append((const char *)&axes[i].tag, 4); fAxisSliders[i].name.appendS32(i); } fAxisSliderCount = axisCount; } } } } inline static constexpr int rows = 2; inline static constexpr int cols = 5; sk_sp typeface[rows][cols]; void updateTypefaces() { sk_sp fontMgr(SkFontMgr::RefDefault()); std::unique_ptr distortableStream( fInfo.distortable ? fInfo.distortable->openStream(nullptr) : nullptr); for (int row = 0; row < rows; ++row) { for (int col = 0; col < cols; ++col) { using Coordinate = SkFontArguments::VariationPosition::Coordinate; int coordinateCount; std::unique_ptr coordinates; if (fOverride) { coordinateCount = fAxisSliderCount; coordinates = std::make_unique(coordinateCount); for (size_t i = 0; i < fAxisSliderCount; ++i) { coordinates[i].axis = fAxisSliders[i].axis; coordinates[i].value = fAxisSliders[i].control[0]; } } else { coordinateCount = 2; coordinates = std::make_unique(coordinateCount); SkScalar styleValue = SkScalarInterp(fInfo.axisMin, fInfo.axisMax, SkScalar(row*cols + col) / (rows*cols)); coordinates[0] = {fInfo.axisTag, styleValue}; coordinates[1] = {fInfo.axisTag, styleValue}; } SkFontArguments::VariationPosition position = {coordinates.get(), coordinateCount}; typeface[row][col] = [&]() -> sk_sp { if (row == 0 && fInfo.distortable) { return fInfo.distortable->makeClone( SkFontArguments().setVariationDesignPosition(position)); } if (distortableStream) { return fontMgr->makeFromStream(distortableStream->duplicate(), SkFontArguments().setVariationDesignPosition(position)); } return nullptr; }(); } } fDirty = false; } DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override { if (fDirty) { this->updateTypefaces(); } SkPaint paint; paint.setAntiAlias(true); SkFont font; font.setEdging(SkFont::Edging::kSubpixelAntiAlias); const char* text = "abc"; const size_t textLen = strlen(text); for (int row = 0; row < rows; ++row) { for (int col = 0; col < cols; ++col) { SkScalar x = SkIntToScalar(10); SkScalar y = SkIntToScalar(20); font.setTypeface(typeface[row][col] ? typeface[row][col] : nullptr); SkAutoCanvasRestore acr(canvas, true); canvas->translate(SkIntToScalar(30 + col * 100), SkIntToScalar(20)); canvas->rotate(SkIntToScalar(col * 5), x, y * 10); { SkPaint p; p.setAntiAlias(true); SkRect r; r.setLTRB(x - 3, 15, x - 1, 280); canvas->drawRect(r, p); } for (int ps = 6; ps <= 22; ps++) { font.setSize(SkIntToScalar(ps)); canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, x, y, font, paint); y += font.getMetrics(nullptr); } } canvas->translate(0, SkIntToScalar(360)); font.setSubpixel(true); font.setLinearMetrics(true); font.setBaselineSnap(false); } return DrawResult::kOk; } }; ////////////////////////////////////////////////////////////////////////////// DEF_GM( return new FontScalerDistortableGM; ) } // namespace skiagm