1 /* 2 * Copyright 2017 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "gm/gm.h" 9 #include "include/core/SkCanvas.h" 10 #include "include/core/SkColor.h" 11 #include "include/core/SkColorSpace.h" 12 #include "include/core/SkFont.h" 13 #include "include/core/SkImageInfo.h" 14 #include "include/core/SkMatrix.h" 15 #include "include/core/SkPaint.h" 16 #include "include/core/SkRect.h" 17 #include "include/core/SkRefCnt.h" 18 #include "include/core/SkScalar.h" 19 #include "include/core/SkSize.h" 20 #include "include/core/SkString.h" 21 #include "include/core/SkSurface.h" 22 #include "include/core/SkSurfaceProps.h" 23 #include "include/core/SkTextBlob.h" 24 #include "include/core/SkTypes.h" 25 #include "include/gpu/GpuTypes.h" 26 #include "include/gpu/ganesh/SkSurfaceGanesh.h" 27 #include "include/private/base/SkTArray.h" 28 #include "tools/ToolUtils.h" 29 #include "tools/fonts/FontToolUtils.h" 30 31 #include <initializer_list> 32 33 using namespace skia_private; 34 35 /** 36 * This GM tests reusing the same text blobs with distance fields rendering using various 37 * combinations of perspective and non-perspetive matrices, scissor clips, and different x,y params 38 * passed to the draw. 39 */ 40 class DFTextBlobPerspGM : public skiagm::GM { 41 public: DFTextBlobPerspGM()42 DFTextBlobPerspGM() { this->setBGColor(0xFFFFFFFF); } 43 44 protected: getName() const45 SkString getName() const override { return SkString("dftext_blob_persp"); } 46 getISize()47 SkISize getISize() override { return SkISize::Make(900, 350); } 48 onOnceBeforeDraw()49 void onOnceBeforeDraw() override { 50 for (int i = 0; i < 3; ++i) { 51 SkFont font = ToolUtils::DefaultPortableFont(); 52 font.setSize(32); 53 font.setEdging(i == 0 ? SkFont::Edging::kAlias : 54 (i == 1 ? SkFont::Edging::kAntiAlias : 55 SkFont::Edging::kSubpixelAntiAlias)); 56 font.setSubpixel(true); 57 SkTextBlobBuilder builder; 58 ToolUtils::add_to_text_blob(&builder, "SkiaText", font, 0, 0); 59 fBlobs.emplace_back(builder.make()); 60 } 61 } 62 onDraw(SkCanvas * inputCanvas)63 void onDraw(SkCanvas* inputCanvas) override { 64 // set up offscreen rendering with distance field text 65 auto ctx = inputCanvas->recordingContext(); 66 SkISize size = this->getISize(); 67 if (!inputCanvas->getBaseLayerSize().isEmpty()) { 68 size = inputCanvas->getBaseLayerSize(); 69 } 70 SkImageInfo info = SkImageInfo::MakeN32(size.width(), size.height(), kPremul_SkAlphaType, 71 inputCanvas->imageInfo().refColorSpace()); 72 SkSurfaceProps inputProps; 73 inputCanvas->getProps(&inputProps); 74 SkSurfaceProps props(SkSurfaceProps::kUseDeviceIndependentFonts_Flag | inputProps.flags(), 75 inputProps.pixelGeometry()); 76 auto surface = SkSurfaces::RenderTarget(ctx, skgpu::Budgeted::kNo, info, 0, &props); 77 SkCanvas* canvas = surface ? surface->getCanvas() : inputCanvas; 78 // init our new canvas with the old canvas's matrix 79 canvas->setMatrix(inputCanvas->getLocalToDeviceAs3x3()); 80 SkScalar x = 0, y = 0; 81 SkScalar maxH = 0; 82 for (auto twm : {TranslateWithMatrix::kNo, TranslateWithMatrix::kYes}) { 83 for (auto pm : {PerspMode::kNone, PerspMode::kX, PerspMode::kY, PerspMode::kXY}) { 84 for (auto& blob : fBlobs) { 85 for (bool clip : {false, true}) { 86 SkAutoCanvasRestore acr(canvas, true); 87 SkScalar w = blob->bounds().width(); 88 SkScalar h = blob->bounds().height(); 89 if (clip) { 90 auto rect = 91 SkRect::MakeXYWH(x + 5, y + 5, w * 3.f / 4.f, h * 3.f / 4.f); 92 canvas->clipRect(rect, false); 93 } 94 this->drawBlob(canvas, blob.get(), SK_ColorBLACK, x, y + h, pm, twm); 95 x += w + 20.f; 96 maxH = std::max(h, maxH); 97 } 98 } 99 x = 0; 100 y += maxH + 20.f; 101 maxH = 0; 102 } 103 } 104 // render offscreen buffer 105 if (surface) { 106 SkAutoCanvasRestore acr(inputCanvas, true); 107 // since we prepended this matrix already, we blit using identity 108 inputCanvas->resetMatrix(); 109 inputCanvas->drawImage(surface->makeImageSnapshot().get(), 0, 0); 110 } 111 } 112 113 private: 114 enum class PerspMode { kNone, kX, kY, kXY }; 115 116 enum class TranslateWithMatrix : bool { kNo, kYes }; 117 drawBlob(SkCanvas * canvas,SkTextBlob * blob,SkColor color,SkScalar x,SkScalar y,PerspMode perspMode,TranslateWithMatrix translateWithMatrix)118 void drawBlob(SkCanvas* canvas, SkTextBlob* blob, SkColor color, SkScalar x, SkScalar y, 119 PerspMode perspMode, TranslateWithMatrix translateWithMatrix) { 120 canvas->save(); 121 SkMatrix persp = SkMatrix::I(); 122 switch (perspMode) { 123 case PerspMode::kNone: 124 break; 125 case PerspMode::kX: 126 persp.setPerspX(0.005f); 127 break; 128 case PerspMode::kY: 129 persp.setPerspY(00.005f); 130 break; 131 case PerspMode::kXY: 132 persp.setPerspX(-0.001f); 133 persp.setPerspY(-0.0015f); 134 break; 135 } 136 persp = SkMatrix::Concat(persp, SkMatrix::Translate(-x, -y)); 137 persp = SkMatrix::Concat(SkMatrix::Translate(x, y), persp); 138 canvas->concat(persp); 139 if (TranslateWithMatrix::kYes == translateWithMatrix) { 140 canvas->translate(x, y); 141 x = 0; 142 y = 0; 143 } 144 SkPaint paint; 145 paint.setColor(color); 146 canvas->drawTextBlob(blob, x, y, paint); 147 canvas->restore(); 148 } 149 150 TArray<sk_sp<SkTextBlob>> fBlobs; 151 using INHERITED = skiagm::GM; 152 }; 153 154 DEF_GM(return new DFTextBlobPerspGM;) 155