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_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