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.h" 9#include "sk_tool_utils.h" 10#if SK_SUPPORT_GPU 11#include "GrContext.h" 12#include "GrRenderTargetContextPriv.h" 13#include "effects/GrRRectEffect.h" 14#include "ops/GrDrawOp.h" 15#include "ops/GrRectOpFactory.h" 16#endif 17#include "SkRRect.h" 18 19namespace skiagm { 20 21/////////////////////////////////////////////////////////////////////////////// 22 23class RRectGM : public GM { 24public: 25 enum Type { 26 kBW_Draw_Type, 27 kAA_Draw_Type, 28 kBW_Clip_Type, 29 kAA_Clip_Type, 30 kEffect_Type, 31 }; 32 RRectGM(Type type) : fType(type) { } 33 34protected: 35 36 void onOnceBeforeDraw() override { 37 this->setBGColor(sk_tool_utils::color_to_565(0xFFDDDDDD)); 38 this->setUpRRects(); 39 } 40 41 SkString onShortName() override { 42 SkString name("rrect"); 43 switch (fType) { 44 case kBW_Draw_Type: 45 name.append("_draw_bw"); 46 break; 47 case kAA_Draw_Type: 48 name.append("_draw_aa"); 49 break; 50 case kBW_Clip_Type: 51 name.append("_clip_bw"); 52 break; 53 case kAA_Clip_Type: 54 name.append("_clip_aa"); 55 break; 56 case kEffect_Type: 57 name.append("_effect"); 58 break; 59 } 60 return name; 61 } 62 63 SkISize onISize() override { return SkISize::Make(kImageWidth, kImageHeight); } 64 65 void onDraw(SkCanvas* canvas) override { 66 GrRenderTargetContext* renderTargetContext = 67 canvas->internal_private_accessTopLayerRenderTargetContext(); 68 if (kEffect_Type == fType && !renderTargetContext) { 69 skiagm::GM::DrawGpuOnlyMessage(canvas); 70 return; 71 } 72 73 SkPaint paint; 74 if (kAA_Draw_Type == fType) { 75 paint.setAntiAlias(true); 76 } 77 78 const SkRect kMaxTileBound = SkRect::MakeWH(SkIntToScalar(kTileX), 79 SkIntToScalar(kTileY)); 80#ifdef SK_DEBUG 81 const SkRect kMaxImageBound = SkRect::MakeWH(SkIntToScalar(kImageWidth), 82 SkIntToScalar(kImageHeight)); 83#endif 84 85#if SK_SUPPORT_GPU 86 int lastEdgeType = (kEffect_Type == fType) ? (int) GrClipEdgeType::kLast: 0; 87#else 88 int lastEdgeType = 0; 89#endif 90 91 int y = 1; 92 for (int et = 0; et <= lastEdgeType; ++et) { 93 int x = 1; 94 for (int curRRect = 0; curRRect < kNumRRects; ++curRRect) { 95 bool drew = true; 96#ifdef SK_DEBUG 97 SkASSERT(kMaxTileBound.contains(fRRects[curRRect].getBounds())); 98 SkRect imageSpaceBounds = fRRects[curRRect].getBounds(); 99 imageSpaceBounds.offset(SkIntToScalar(x), SkIntToScalar(y)); 100 SkASSERT(kMaxImageBound.contains(imageSpaceBounds)); 101#endif 102 canvas->save(); 103 canvas->translate(SkIntToScalar(x), SkIntToScalar(y)); 104 if (kEffect_Type == fType) { 105#if SK_SUPPORT_GPU 106 SkRRect rrect = fRRects[curRRect]; 107 rrect.offset(SkIntToScalar(x), SkIntToScalar(y)); 108 GrClipEdgeType edgeType = (GrClipEdgeType) et; 109 const auto& caps = *renderTargetContext->caps()->shaderCaps(); 110 auto fp = GrRRectEffect::Make(edgeType, rrect, caps); 111 if (fp) { 112 GrPaint grPaint; 113 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc)); 114 grPaint.addCoverageFragmentProcessor(std::move(fp)); 115 grPaint.setColor4f(GrColor4f(0, 0, 0, 1.f)); 116 117 SkRect bounds = rrect.getBounds(); 118 bounds.outset(2.f, 2.f); 119 120 renderTargetContext->priv().testingOnly_addDrawOp( 121 GrRectOpFactory::MakeNonAAFill(std::move(grPaint), 122 SkMatrix::I(), bounds, 123 GrAAType::kNone)); 124 } else { 125 drew = false; 126 } 127#endif 128 } else if (kBW_Clip_Type == fType || kAA_Clip_Type == fType) { 129 bool aaClip = (kAA_Clip_Type == fType); 130 canvas->clipRRect(fRRects[curRRect], aaClip); 131 canvas->drawRect(kMaxTileBound, paint); 132 } else { 133 canvas->drawRRect(fRRects[curRRect], paint); 134 } 135 canvas->restore(); 136 if (drew) { 137 x = x + kTileX; 138 if (x > kImageWidth) { 139 x = 1; 140 y += kTileY; 141 } 142 } 143 } 144 if (x != 1) { 145 y += kTileY; 146 } 147 } 148 } 149 150 void setUpRRects() { 151 // each RRect must fit in a 0x0 -> (kTileX-2)x(kTileY-2) block. These will be tiled across 152 // the screen in kTileX x kTileY tiles. The extra empty pixels on each side are for AA. 153 154 // simple cases 155 fRRects[0].setRect(SkRect::MakeWH(kTileX-2, kTileY-2)); 156 fRRects[1].setOval(SkRect::MakeWH(kTileX-2, kTileY-2)); 157 fRRects[2].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 10, 10); 158 fRRects[3].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 10, 5); 159 // small circular corners are an interesting test case for gpu clipping 160 fRRects[4].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 1, 1); 161 fRRects[5].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 0.5f, 0.5f); 162 fRRects[6].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 0.2f, 0.2f); 163 164 // The first complex case needs special handling since it is a square 165 fRRects[kNumSimpleCases].setRectRadii(SkRect::MakeWH(kTileY-2, kTileY-2), gRadii[0]); 166 for (size_t i = 1; i < SK_ARRAY_COUNT(gRadii); ++i) { 167 fRRects[kNumSimpleCases+i].setRectRadii(SkRect::MakeWH(kTileX-2, kTileY-2), gRadii[i]); 168 } 169 } 170 171private: 172 Type fType; 173 174 static constexpr int kImageWidth = 640; 175 static constexpr int kImageHeight = 480; 176 177 static constexpr int kTileX = 80; 178 static constexpr int kTileY = 40; 179 180 static constexpr int kNumSimpleCases = 7; 181 static constexpr int kNumComplexCases = 35; 182 static const SkVector gRadii[kNumComplexCases][4]; 183 184 static constexpr int kNumRRects = kNumSimpleCases + kNumComplexCases; 185 SkRRect fRRects[kNumRRects]; 186 187 typedef GM INHERITED; 188}; 189 190// Radii for the various test cases. Order is UL, UR, LR, LL 191const SkVector RRectGM::gRadii[kNumComplexCases][4] = { 192 // a circle 193 { { kTileY, kTileY }, { kTileY, kTileY }, { kTileY, kTileY }, { kTileY, kTileY } }, 194 195 // odd ball cases 196 { { 8, 8 }, { 32, 32 }, { 8, 8 }, { 32, 32 } }, 197 { { 16, 8 }, { 8, 16 }, { 16, 8 }, { 8, 16 } }, 198 { { 0, 0 }, { 16, 16 }, { 8, 8 }, { 32, 32 } }, 199 200 // UL 201 { { 30, 30 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 202 { { 30, 15 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 203 { { 15, 30 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 204 205 // UR 206 { { 0, 0 }, { 30, 30 }, { 0, 0 }, { 0, 0 } }, 207 { { 0, 0 }, { 30, 15 }, { 0, 0 }, { 0, 0 } }, 208 { { 0, 0 }, { 15, 30 }, { 0, 0 }, { 0, 0 } }, 209 210 // LR 211 { { 0, 0 }, { 0, 0 }, { 30, 30 }, { 0, 0 } }, 212 { { 0, 0 }, { 0, 0 }, { 30, 15 }, { 0, 0 } }, 213 { { 0, 0 }, { 0, 0 }, { 15, 30 }, { 0, 0 } }, 214 215 // LL 216 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 30, 30 } }, 217 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 30, 15 } }, 218 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 15, 30 } }, 219 220 // over-sized radii 221 { { 0, 0 }, { 100, 400 }, { 0, 0 }, { 0, 0 } }, 222 { { 0, 0 }, { 400, 400 }, { 0, 0 }, { 0, 0 } }, 223 { { 400, 400 }, { 400, 400 }, { 400, 400 }, { 400, 400 } }, 224 225 // circular corner tabs 226 { { 0, 0 }, { 20, 20 }, { 20, 20 }, { 0, 0 } }, 227 { { 20, 20 }, { 20, 20 }, { 0, 0 }, { 0, 0 } }, 228 { { 0, 0 }, { 0, 0 }, { 20, 20 }, { 20, 20 } }, 229 { { 20, 20 }, { 0, 0 }, { 0, 0 }, { 20, 20 } }, 230 231 // small radius circular corner tabs 232 { { 0, 0 }, { 0.2f, 0.2f }, { 0.2f, 0.2f }, { 0, 0 } }, 233 { { 0.3f, 0.3f }, { 0.3f, .3f }, { 0, 0 }, { 0, 0 } }, 234 235 // single circular corner cases 236 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 15, 15 } }, 237 { { 0, 0 }, { 0, 0 }, { 15, 15 }, { 0, 0 } }, 238 { { 0, 0 }, { 15, 15 }, { 0, 0 }, { 0, 0 } }, 239 { { 15, 15 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 240 241 // nine patch elliptical 242 { { 5, 7 }, { 8, 7 }, { 8, 12 }, { 5, 12 } }, 243 { { 0, 7 }, { 8, 7 }, { 8, 12 }, { 0, 12 } }, 244 245 // nine patch elliptical, small radii 246 { { 0.4f, 7 }, { 8, 7 }, { 8, 12 }, { 0.4f, 12 } }, 247 { { 0.4f, 0.4f }, { 8, 0.4f }, { 8, 12 }, { 0.4f, 12 } }, 248 { { 20, 0.4f }, { 18, 0.4f }, { 18, 0.4f }, { 20, 0.4f } }, 249 { { 0.3f, 0.4f }, { 0.3f, 0.4f }, { 0.3f, 0.4f }, { 0.3f, 0.4f } }, 250 251}; 252 253/////////////////////////////////////////////////////////////////////////////// 254 255DEF_GM( return new RRectGM(RRectGM::kAA_Draw_Type); ) 256DEF_GM( return new RRectGM(RRectGM::kBW_Draw_Type); ) 257DEF_GM( return new RRectGM(RRectGM::kAA_Clip_Type); ) 258DEF_GM( return new RRectGM(RRectGM::kBW_Clip_Type); ) 259#if SK_SUPPORT_GPU 260DEF_GM( return new RRectGM(RRectGM::kEffect_Type); ) 261#endif 262 263} 264