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 }; RRectGM(Type type)29 RRectGM(Type type) : fType(type) { 30 this->setBGColor(0xFFDDDDDD); 31 this->setUpRRects(); 32 } 33 34 protected: onShortName()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 onISize()57 virtual SkISize onISize() SK_OVERRIDE { return SkISize::Make(kImageWidth, kImageHeight); } 58 onGetFlags() const59 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 onDraw(SkCanvas * canvas)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_GrEffectEdgeType: 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 GrEffectEdgeType edgeType = (GrEffectEdgeType) et; 120 SkAutoTUnref<GrEffectRef> effect(GrRRectEffect::Create(edgeType, rrect)); 121 if (effect) { 122 drawState->addCoverageEffect(effect); 123 drawState->setIdentityViewMatrix(); 124 drawState->setRenderTarget(rt); 125 drawState->setColor(0xff000000); 126 127 SkRect bounds = rrect.getBounds(); 128 bounds.outset(2.f, 2.f); 129 130 tt.target()->drawSimpleRect(bounds); 131 } else { 132 drew = false; 133 } 134 #endif 135 } else if (kBW_Clip_Type == fType || kAA_Clip_Type == fType) { 136 bool aaClip = (kAA_Clip_Type == fType); 137 canvas->clipRRect(fRRects[curRRect], SkRegion::kReplace_Op, aaClip); 138 canvas->drawRect(kMaxTileBound, paint); 139 } else { 140 canvas->drawRRect(fRRects[curRRect], paint); 141 } 142 canvas->restore(); 143 if (drew) { 144 x = x + kTileX; 145 if (x > kImageWidth) { 146 x = 1; 147 y += kTileY; 148 } 149 } 150 } 151 if (x != 1) { 152 y += kTileY; 153 } 154 } 155 } 156 setUpRRects()157 void setUpRRects() { 158 // each RRect must fit in a 0x0 -> (kTileX-2)x(kTileY-2) block. These will be tiled across 159 // the screen in kTileX x kTileY tiles. The extra empty pixels on each side are for AA. 160 161 // simple cases 162 fRRects[0].setRect(SkRect::MakeWH(kTileX-2, kTileY-2)); 163 fRRects[1].setOval(SkRect::MakeWH(kTileX-2, kTileY-2)); 164 fRRects[2].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 10, 10); 165 fRRects[3].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 10, 5); 166 // small circular corners are an interesting test case for gpu clipping 167 fRRects[4].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 1, 1); 168 fRRects[5].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 0.5f, 0.5f); 169 fRRects[6].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 0.2f, 0.2f); 170 171 // The first complex case needs special handling since it is a square 172 fRRects[kNumSimpleCases].setRectRadii(SkRect::MakeWH(kTileY-2, kTileY-2), gRadii[0]); 173 for (size_t i = 1; i < SK_ARRAY_COUNT(gRadii); ++i) { 174 fRRects[kNumSimpleCases+i].setRectRadii(SkRect::MakeWH(kTileX-2, kTileY-2), gRadii[i]); 175 } 176 } 177 178 private: 179 Type fType; 180 181 static const int kImageWidth = 640; 182 static const int kImageHeight = 480; 183 184 static const int kTileX = 80; 185 static const int kTileY = 40; 186 187 static const int kNumSimpleCases = 7; 188 static const int kNumComplexCases = 35; 189 static const SkVector gRadii[kNumComplexCases][4]; 190 191 static const int kNumRRects = kNumSimpleCases + kNumComplexCases; 192 SkRRect fRRects[kNumRRects]; 193 194 typedef GM INHERITED; 195 }; 196 197 // Radii for the various test cases. Order is UL, UR, LR, LL 198 const SkVector RRectGM::gRadii[kNumComplexCases][4] = { 199 // a circle 200 { { kTileY, kTileY }, { kTileY, kTileY }, { kTileY, kTileY }, { kTileY, kTileY } }, 201 202 // odd ball cases 203 { { 8, 8 }, { 32, 32 }, { 8, 8 }, { 32, 32 } }, 204 { { 16, 8 }, { 8, 16 }, { 16, 8 }, { 8, 16 } }, 205 { { 0, 0 }, { 16, 16 }, { 8, 8 }, { 32, 32 } }, 206 207 // UL 208 { { 30, 30 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 209 { { 30, 15 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 210 { { 15, 30 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 211 212 // UR 213 { { 0, 0 }, { 30, 30 }, { 0, 0 }, { 0, 0 } }, 214 { { 0, 0 }, { 30, 15 }, { 0, 0 }, { 0, 0 } }, 215 { { 0, 0 }, { 15, 30 }, { 0, 0 }, { 0, 0 } }, 216 217 // LR 218 { { 0, 0 }, { 0, 0 }, { 30, 30 }, { 0, 0 } }, 219 { { 0, 0 }, { 0, 0 }, { 30, 15 }, { 0, 0 } }, 220 { { 0, 0 }, { 0, 0 }, { 15, 30 }, { 0, 0 } }, 221 222 // LL 223 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 30, 30 } }, 224 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 30, 15 } }, 225 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 15, 30 } }, 226 227 // over-sized radii 228 { { 0, 0 }, { 100, 400 }, { 0, 0 }, { 0, 0 } }, 229 { { 0, 0 }, { 400, 400 }, { 0, 0 }, { 0, 0 } }, 230 { { 400, 400 }, { 400, 400 }, { 400, 400 }, { 400, 400 } }, 231 232 // circular corner tabs 233 { { 0, 0 }, { 20, 20 }, { 20, 20 }, { 0, 0 } }, 234 { { 20, 20 }, { 20, 20 }, { 0, 0 }, { 0, 0 } }, 235 { { 0, 0 }, { 0, 0 }, { 20, 20 }, { 20, 20 } }, 236 { { 20, 20 }, { 0, 0 }, { 0, 0 }, { 20, 20 } }, 237 238 // small radius circular corner tabs 239 { { 0, 0 }, { 0.2f, 0.2f }, { 0.2f, 0.2f }, { 0, 0 } }, 240 { { 0.3f, 0.3f }, { 0.3f, .3f }, { 0, 0 }, { 0, 0 } }, 241 242 // single circular corner cases 243 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 15, 15 } }, 244 { { 0, 0 }, { 0, 0 }, { 15, 15 }, { 0, 0 } }, 245 { { 0, 0 }, { 15, 15 }, { 0, 0 }, { 0, 0 } }, 246 { { 15, 15 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 247 248 // nine patch elliptical 249 { { 5, 7 }, { 8, 7 }, { 8, 12 }, { 5, 12 } }, 250 { { 0, 7 }, { 8, 7 }, { 8, 12 }, { 0, 12 } }, 251 252 // nine patch elliptical, small radii 253 { { 0.4f, 7 }, { 8, 7 }, { 8, 12 }, { 0.4f, 12 } }, 254 { { 0.4f, 0.4f }, { 8, 0.4f }, { 8, 12 }, { 0.4f, 12 } }, 255 { { 20, 0.4f }, { 18, 0.4f }, { 18, 0.4f }, { 20, 0.4f } }, 256 { { 0.3f, 0.4f }, { 0.3f, 0.4f }, { 0.3f, 0.4f }, { 0.3f, 0.4f } }, 257 258 }; 259 260 /////////////////////////////////////////////////////////////////////////////// 261 262 DEF_GM( return new RRectGM(RRectGM::kAA_Draw_Type); ) 263 DEF_GM( return new RRectGM(RRectGM::kBW_Draw_Type); ) 264 DEF_GM( return new RRectGM(RRectGM::kAA_Clip_Type); ) 265 DEF_GM( return new RRectGM(RRectGM::kBW_Clip_Type); ) 266 #if SK_SUPPORT_GPU 267 DEF_GM( return new RRectGM(RRectGM::kEffect_Type); ) 268 #endif 269 270 } 271