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