1/* 2* Copyright 2013 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.h" 9#include "SkBlurMask.h" 10#include "SkBlurMaskFilter.h" 11#include "SkCanvas.h" 12#include "SkColorFilter.h" 13#include "SkLayerDrawLooper.h" 14#include "SkPaint.h" 15#include "SkPath.h" 16#include "SkPoint.h" 17#include "SkRect.h" 18#include "SkRRect.h" 19#include "SkString.h" 20#include "SkXfermode.h" 21 22// This GM mimics a blurred RR seen in the wild. 23class BlurRoundRectGM : public skiagm::GM { 24public: 25 BlurRoundRectGM(int width, int height, int radius) 26 : fName("blurroundrect") 27 { 28 SkRect r = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); 29 fRRect.setRectXY(r, SkIntToScalar(radius), SkIntToScalar(radius)); 30 fName.appendf("-WH-%ix%i-corner-%i", width, height, radius); 31 } 32 33 BlurRoundRectGM(int width, int height) 34 : fName("blurroundrect") { 35 fName.appendf("-WH-%ix%i-unevenCorners", width, height); 36 SkVector radii[4]; 37 radii[0].set(SkIntToScalar(30), SkIntToScalar(30)); 38 radii[1].set(SkIntToScalar(10), SkIntToScalar(10)); 39 radii[2].set(SkIntToScalar(30), SkIntToScalar(30)); 40 radii[3].set(SkIntToScalar(10), SkIntToScalar(10)); 41 SkRect r = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); 42 fRRect.setRectRadii(r, radii); 43 } 44 45 SkString onShortName() override { 46 return fName; 47 } 48 49 SkISize onISize() override { 50 return SkISize::Make(SkScalarCeilToInt(fRRect.rect().width()), 51 SkScalarCeilToInt(fRRect.rect().height())); 52 } 53 54 void onDraw(SkCanvas* canvas) override { 55 SkLayerDrawLooper::Builder looperBuilder; 56 { 57 SkLayerDrawLooper::LayerInfo info; 58 info.fPaintBits = SkLayerDrawLooper::kMaskFilter_Bit 59 | SkLayerDrawLooper::kColorFilter_Bit; 60 info.fColorMode = SkXfermode::kSrc_Mode; 61 info.fOffset = SkPoint::Make(SkIntToScalar(-1), SkIntToScalar(0)); 62 info.fPostTranslate = false; 63 SkPaint* paint = looperBuilder.addLayerOnTop(info); 64 SkMaskFilter* maskFilter = SkBlurMaskFilter::Create( 65 kNormal_SkBlurStyle, 66 SkBlurMask::ConvertRadiusToSigma(SK_ScalarHalf), 67 SkBlurMaskFilter::kHighQuality_BlurFlag); 68 paint->setMaskFilter(maskFilter)->unref(); 69 SkColorFilter* colorFilter = SkColorFilter::CreateModeFilter(SK_ColorLTGRAY, 70 SkXfermode::kSrcIn_Mode); 71 paint->setColorFilter(colorFilter)->unref(); 72 paint->setColor(SK_ColorGRAY); 73 } 74 { 75 SkLayerDrawLooper::LayerInfo info; 76 looperBuilder.addLayerOnTop(info); 77 } 78 SkPaint paint; 79 canvas->drawRect(fRRect.rect(), paint); 80 81 paint.setLooper(looperBuilder.detachLooper())->unref(); 82 paint.setColor(SK_ColorCYAN); 83 paint.setAntiAlias(true); 84 85 canvas->drawRRect(fRRect, paint); 86 } 87 88private: 89 SkString fName; 90 SkRRect fRRect; 91 92 typedef skiagm::GM INHERITED; 93}; 94 95#include "SkGradientShader.h" 96/* 97 * Spits out a dummy gradient to test blur with shader on paint 98 */ 99static SkShader* MakeRadial() { 100 SkPoint pts[2] = { 101 { 0, 0 }, 102 { SkIntToScalar(100), SkIntToScalar(100) } 103 }; 104 SkShader::TileMode tm = SkShader::kClamp_TileMode; 105 const SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, }; 106 const SkScalar pos[] = { SK_Scalar1/4, SK_Scalar1*3/4 }; 107 SkMatrix scale; 108 scale.setScale(0.5f, 0.5f); 109 scale.postTranslate(5.f, 5.f); 110 SkPoint center0, center1; 111 center0.set(SkScalarAve(pts[0].fX, pts[1].fX), 112 SkScalarAve(pts[0].fY, pts[1].fY)); 113 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5), 114 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4)); 115 return SkGradientShader::CreateTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7, 116 center0, (pts[1].fX - pts[0].fX) / 2, 117 colors, pos, SK_ARRAY_COUNT(colors), tm, 118 0, &scale); 119} 120 121// Simpler blurred RR test cases where all the radii are the same. 122class SimpleBlurRoundRectGM : public skiagm::GM { 123public: 124 SimpleBlurRoundRectGM() 125 : fName("simpleblurroundrect") { 126 } 127 128protected: 129 130 SkString onShortName() override { 131 return fName; 132 } 133 134 SkISize onISize() override { 135 return SkISize::Make(1000, 500); 136 } 137 138 void onDraw(SkCanvas* canvas) override { 139 canvas->scale(1.5f, 1.5f); 140 canvas->translate(50,50); 141 142 const float blurRadii[] = { 1,5,10,20 }; 143 const int cornerRadii[] = { 1,5,10,20 }; 144 const SkRect r = SkRect::MakeWH(SkIntToScalar(25), SkIntToScalar(25)); 145 for (size_t i = 0; i < SK_ARRAY_COUNT(blurRadii); ++i) { 146 SkAutoCanvasRestore autoRestore(canvas, true); 147 canvas->translate(0, (r.height() + SkIntToScalar(50)) * i); 148 for (size_t j = 0; j < SK_ARRAY_COUNT(cornerRadii); ++j) { 149 for (int k = 0; k <= 1; k++) { 150 SkMaskFilter* filter = SkBlurMaskFilter::Create( 151 kNormal_SkBlurStyle, 152 SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(blurRadii[i])), 153 SkBlurMaskFilter::kHighQuality_BlurFlag); 154 SkPaint paint; 155 paint.setColor(SK_ColorBLACK); 156 paint.setMaskFilter(filter)->unref(); 157 158 bool useRadial = SkToBool(k); 159 if (useRadial) { 160 paint.setShader(MakeRadial())->unref(); 161 } 162 163 SkRRect rrect; 164 rrect.setRectXY(r, SkIntToScalar(cornerRadii[j]), 165 SkIntToScalar(cornerRadii[j])); 166 canvas->drawRRect(rrect, paint); 167 canvas->translate(r.width() + SkIntToScalar(50), 0); 168 } 169 } 170 } 171 } 172private: 173 const SkString fName; 174 175 typedef skiagm::GM INHERITED; 176}; 177 178// Create one with dimensions/rounded corners based on the skp 179// 180// TODO(scroggo): Disabled in an attempt to rememdy 181// https://code.google.com/p/skia/issues/detail?id=1801 ('Win7 Test bots all failing GenerateGMs: 182// ran wrong number of tests') 183//DEF_GM(return new BlurRoundRectGM(600, 5514, 6);) 184 185// Rounded rect with two opposite corners with large radii, the other two 186// small. 187DEF_GM(return new BlurRoundRectGM(100, 100);) 188 189DEF_GM(return new SimpleBlurRoundRectGM();) 190