Home | History | Annotate | Download | only in gm
      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_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 
    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