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