1 /* 2 * Copyright 2012 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/SkBitmap.h" 10 #include "include/core/SkCanvas.h" 11 #include "include/core/SkColor.h" 12 #include "include/core/SkFont.h" 13 #include "include/core/SkImageFilter.h" 14 #include "include/core/SkPaint.h" 15 #include "include/core/SkPoint.h" 16 #include "include/core/SkRect.h" 17 #include "include/core/SkScalar.h" 18 #include "include/core/SkShader.h" 19 #include "include/core/SkSize.h" 20 #include "include/core/SkString.h" 21 #include "include/core/SkTileMode.h" 22 #include "include/core/SkTypeface.h" 23 #include "include/effects/SkGradientShader.h" 24 #include "include/effects/SkImageFilters.h" 25 #include "src/gpu/effects/GrMatrixConvolutionEffect.h" 26 #include "tools/ToolUtils.h" 27 28 #include <vector> 29 30 namespace skiagm { 31 32 enum KernelFixture { 33 kBasic_KernelFixture, 34 kLarge_KernelFixture 35 }; 36 37 class MatrixConvolutionGM : public GM { 38 public: MatrixConvolutionGM(SkColor colorOne,SkColor colorTwo,KernelFixture kernelFixture,const char * nameSuffix)39 MatrixConvolutionGM(SkColor colorOne, SkColor colorTwo, KernelFixture kernelFixture, const char* nameSuffix) 40 : fNameSuffix(nameSuffix), 41 fKernelFixture(kernelFixture) { 42 this->setBGColor(0x00000000); 43 fColors[0] = colorOne; 44 fColors[1] = colorTwo; 45 } 46 47 protected: 48 onShortName()49 SkString onShortName() override { 50 return SkStringPrintf("matrixconvolution%s", fNameSuffix); 51 } 52 makeBitmap()53 void makeBitmap() { 54 // Draw our bitmap in N32, so legacy devices get "premul" values they understand 55 auto surf = SkSurface::MakeRasterN32Premul(80, 80); 56 SkPaint paint; 57 paint.setColor(0xFFFFFFFF); 58 SkPoint pts[2] = { {0, 0}, 59 {0, 80.0f} }; 60 SkScalar pos[2] = { 0, 80.0f }; 61 paint.setShader(SkGradientShader::MakeLinear( 62 pts, fColors, pos, 2, SkTileMode::kClamp)); 63 SkFont font(ToolUtils::create_portable_typeface(), 180.0f); 64 surf->getCanvas()->drawString("e", -10.0f, 80.0f, font, paint); 65 fImage = surf->makeImageSnapshot(); 66 } 67 onISize()68 SkISize onISize() override { 69 return SkISize::Make(500, 300); 70 } 71 makeFilter(const SkIPoint & kernelOffset,SkTileMode tileMode,bool convolveAlpha,const SkIRect * cropRect=nullptr)72 sk_sp<SkImageFilter> makeFilter(const SkIPoint &kernelOffset, SkTileMode tileMode, 73 bool convolveAlpha, const SkIRect *cropRect = nullptr) { 74 switch (fKernelFixture) { 75 case kBasic_KernelFixture: { 76 // All 1s except center value, which is -7 (sum of 1). 77 std::vector<SkScalar> kernel(9, SkIntToScalar(1)); 78 kernel[4] = SkIntToScalar(-7); 79 return SkImageFilters::MatrixConvolution({3,3}, kernel.data(), /* gain */ 0.3f, /* bias */ SkIntToScalar(100), kernelOffset, tileMode, convolveAlpha, nullptr, cropRect); 80 } 81 case kLarge_KernelFixture: { 82 static_assert(49 > GrMatrixConvolutionEffect::kMaxUniformSize); 83 // All 1s except center value, which is -47 (sum of 1). 84 std::vector<SkScalar> kernel(49, SkIntToScalar(1)); 85 kernel[24] = SkIntToScalar(-47); 86 return SkImageFilters::MatrixConvolution({7,7}, kernel.data(), /* gain */ 0.3f, /* bias */ SkIntToScalar(100), kernelOffset, tileMode, convolveAlpha, nullptr, cropRect); 87 } 88 default: 89 return nullptr; 90 } 91 } 92 draw(SkCanvas * canvas,int x,int y,const SkIPoint & kernelOffset,SkTileMode tileMode,bool convolveAlpha,const SkIRect * cropRect=nullptr)93 void draw(SkCanvas* canvas, int x, int y, const SkIPoint& kernelOffset, 94 SkTileMode tileMode, bool convolveAlpha, 95 const SkIRect* cropRect = nullptr) { 96 SkPaint paint; 97 paint.setImageFilter(this->makeFilter(kernelOffset, tileMode, convolveAlpha, cropRect)); 98 canvas->save(); 99 canvas->translate(SkIntToScalar(x), SkIntToScalar(y)); 100 const SkRect layerBounds = SkRect::Make(fImage->bounds()); 101 canvas->clipRect(layerBounds); 102 // This GM is, in part, intended to display the wrapping behavior of the 103 // matrix image filter. The only (rational) way to achieve that for repeat mode 104 // is to create a tight layer. 105 canvas->saveLayer(layerBounds, &paint); 106 canvas->drawImage(fImage, 0, 0); 107 canvas->restore(); 108 canvas->restore(); 109 } 110 onOnceBeforeDraw()111 void onOnceBeforeDraw() override { 112 this->makeBitmap(); 113 } 114 onDraw(SkCanvas * canvas)115 void onDraw(SkCanvas* canvas) override { 116 canvas->clear(SK_ColorBLACK); 117 SkIPoint kernelOffset = SkIPoint::Make(1, 0); 118 SkIRect rect = fImage->bounds(); 119 for (int x = 10; x < 310; x += 100) { 120 this->draw(canvas, x, 10, kernelOffset, SkTileMode::kClamp, true, &rect); 121 this->draw(canvas, x, 110, kernelOffset, SkTileMode::kDecal, true, &rect); 122 this->draw(canvas, x, 210, kernelOffset, SkTileMode::kRepeat, true, &rect); 123 kernelOffset.fY++; 124 } 125 kernelOffset.fY = 1; 126 SkIRect smallRect = SkIRect::MakeXYWH(10, 5, 60, 60); 127 this->draw(canvas, 310, 10, kernelOffset, SkTileMode::kClamp, true, &smallRect); 128 this->draw(canvas, 310, 110, kernelOffset, SkTileMode::kDecal, true, &smallRect); 129 this->draw(canvas, 310, 210, kernelOffset, SkTileMode::kRepeat, true, &smallRect); 130 131 this->draw(canvas, 410, 10, kernelOffset, SkTileMode::kClamp, false, &rect); 132 this->draw(canvas, 410, 110, kernelOffset, SkTileMode::kDecal, false, &rect); 133 this->draw(canvas, 410, 210, kernelOffset, SkTileMode::kRepeat, false, &rect); 134 } 135 136 private: 137 sk_sp<SkImage> fImage; 138 SkColor fColors[2]; 139 const char* fNameSuffix; 140 KernelFixture fKernelFixture; 141 142 using INHERITED = GM; 143 }; 144 145 ////////////////////////////////////////////////////////////////////////////// 146 147 DEF_GM(return new MatrixConvolutionGM(0xFFFFFFFF, 0x40404040, KernelFixture::kBasic_KernelFixture, "");) 148 DEF_GM(return new MatrixConvolutionGM(0xFFFF0000, 0xFF00FF00, KernelFixture::kBasic_KernelFixture, "_color");) 149 DEF_GM(return new MatrixConvolutionGM(0xFFFFFFFF, 0x40404040, KernelFixture::kLarge_KernelFixture, "_big");) 150 DEF_GM(return new MatrixConvolutionGM(0xFFFF0000, 0xFF00FF00, KernelFixture::kLarge_KernelFixture, "_big_color");) 151 152 } // namespace skiagm 153