/* * Copyright 2017 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "gm.h" #include "Resources.h" #include "SkCanvas.h" #include "SkSurface.h" #include "SkTextBlob.h" #include "SkTypeface.h" #include "sk_tool_utils.h" /** * This GM tests reusing the same text blobs with distance fields rendering using various * combinations of perspective and non-perspetive matrices, scissor clips, and different x,y params * passed to the draw. */ class DFTextBlobPerspGM : public skiagm::GM { public: DFTextBlobPerspGM() { this->setBGColor(0xFFFFFFFF); } protected: SkString onShortName() override { SkString name("dftext_blob_persp"); name.append(sk_tool_utils::platform_font_manager()); return name; } SkISize onISize() override { return SkISize::Make(900, 350); } void onOnceBeforeDraw() override { for (int i = 0; i < 3; ++i) { SkFont font; font.setSize(32); font.setEdging(i == 0 ? SkFont::Edging::kAlias : (i == 1 ? SkFont::Edging::kAntiAlias : SkFont::Edging::kSubpixelAntiAlias)); font.setSubpixel(true); SkTextBlobBuilder builder; sk_tool_utils::add_to_text_blob(&builder, "SkiaText", font, 0, 0); fBlobs.emplace_back(builder.make()); } } void onDraw(SkCanvas* inputCanvas) override { // set up offscreen rendering with distance field text GrContext* ctx = inputCanvas->getGrContext(); SkISize size = this->onISize(); if (!inputCanvas->getBaseLayerSize().isEmpty()) { size = inputCanvas->getBaseLayerSize(); } SkImageInfo info = SkImageInfo::MakeN32(size.width(), size.height(), kPremul_SkAlphaType, inputCanvas->imageInfo().refColorSpace()); SkSurfaceProps props(SkSurfaceProps::kUseDeviceIndependentFonts_Flag, SkSurfaceProps::kLegacyFontHost_InitType); auto surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info, 0, &props); SkCanvas* canvas = surface ? surface->getCanvas() : inputCanvas; // init our new canvas with the old canvas's matrix canvas->setMatrix(inputCanvas->getTotalMatrix()); SkScalar x = 0, y = 0; SkScalar maxH = 0; for (auto twm : {TranslateWithMatrix::kNo, TranslateWithMatrix::kYes}) { for (auto pm : {PerspMode::kNone, PerspMode::kX, PerspMode::kY, PerspMode::kXY}) { for (auto& blob : fBlobs) { for (bool clip : {false, true}) { canvas->save(); SkScalar w = blob->bounds().width(); SkScalar h = blob->bounds().height(); if (clip) { auto rect = SkRect::MakeXYWH(x + 5, y + 5, w * 3.f / 4.f, h * 3.f / 4.f); canvas->clipRect(rect, false); } this->drawBlob(canvas, blob.get(), SK_ColorBLACK, x, y + h, pm, twm); x += w + 20.f; maxH = SkTMax(h, maxH); canvas->restore(); } } x = 0; y += maxH + 20.f; maxH = 0; } } // render offscreen buffer if (surface) { SkAutoCanvasRestore acr(inputCanvas, true); // since we prepended this matrix already, we blit using identity inputCanvas->resetMatrix(); inputCanvas->drawImage(surface->makeImageSnapshot().get(), 0, 0, nullptr); } } private: enum class PerspMode { kNone, kX, kY, kXY }; enum class TranslateWithMatrix : bool { kNo, kYes }; void drawBlob(SkCanvas* canvas, SkTextBlob* blob, SkColor color, SkScalar x, SkScalar y, PerspMode perspMode, TranslateWithMatrix translateWithMatrix) { canvas->save(); SkMatrix persp = SkMatrix::I(); switch (perspMode) { case PerspMode::kNone: break; case PerspMode::kX: persp.setPerspX(0.005f); break; case PerspMode::kY: persp.setPerspY(00.005f); break; case PerspMode::kXY: persp.setPerspX(-0.001f); persp.setPerspY(-0.0015f); break; } persp = SkMatrix::Concat(persp, SkMatrix::MakeTrans(-x, -y)); persp = SkMatrix::Concat(SkMatrix::MakeTrans(x, y), persp); canvas->concat(persp); if (TranslateWithMatrix::kYes == translateWithMatrix) { canvas->translate(x, y); x = 0; y = 0; } SkPaint paint; paint.setColor(color); canvas->drawTextBlob(blob, x, y, paint); canvas->restore(); } SkTArray<sk_sp<SkTextBlob>> fBlobs; typedef skiagm::GM INHERITED; }; DEF_GM(return new DFTextBlobPerspGM;)