Home | History | Annotate | Download | only in gm
      1 
      2 /*
      3  * Copyright 2013 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 #include "gm.h"
      9 #include "SkBitmap.h"
     10 #include "SkGradientShader.h"
     11 #include "SkXfermode.h"
     12 #include "SkColorPriv.h"
     13 
     14 #if SK_SUPPORT_GPU
     15 #include "GrContext.h"
     16 #include "SkGpuDevice.h"
     17 #endif
     18 
     19 namespace skiagm {
     20 
     21 /**
     22  * This tests drawing device-covering rects with solid colors and bitmap shaders over a
     23  * checkerboard background using different xfermodes.
     24  */
     25 class Xfermodes3GM : public GM {
     26 public:
     27     Xfermodes3GM() {}
     28 
     29 protected:
     30     virtual SkString onShortName() SK_OVERRIDE {
     31         return SkString("xfermodes3");
     32     }
     33 
     34     virtual SkISize onISize() SK_OVERRIDE {
     35         return make_isize(630, 1215);
     36     }
     37 
     38     virtual void onDrawBackground(SkCanvas* canvas) SK_OVERRIDE {
     39         SkPaint bgPaint;
     40         bgPaint.setColor(0xFF70D0E0);
     41         canvas->drawPaint(bgPaint);
     42     }
     43 
     44     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
     45         canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
     46 
     47         SkPaint labelP;
     48         labelP.setAntiAlias(true);
     49 
     50         static const SkColor kSolidColors[] = {
     51             SK_ColorTRANSPARENT,
     52             SK_ColorBLUE,
     53             0x80808000
     54         };
     55 
     56         static const SkColor kBmpAlphas[] = {
     57             0xff,
     58             0x80,
     59         };
     60 
     61         SkAutoTUnref<SkCanvas> tempCanvas(this->possiblyCreateTempCanvas(canvas, kSize, kSize));
     62 
     63         int test = 0;
     64         int x = 0, y = 0;
     65         static const struct { SkPaint::Style fStyle; SkScalar fWidth; } kStrokes[] = {
     66             {SkPaint::kFill_Style, 0},
     67             {SkPaint::kStroke_Style, SkIntToScalar(kSize) / 2},
     68         };
     69         for (size_t s = 0; s < SK_ARRAY_COUNT(kStrokes); ++s) {
     70             for (size_t m = 0; m <= SkXfermode::kLastMode; ++m) {
     71                 SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(m);
     72                 canvas->drawText(SkXfermode::ModeName(mode),
     73                                  strlen(SkXfermode::ModeName(mode)),
     74                                  SkIntToScalar(x),
     75                                  SkIntToScalar(y + kSize + 3) + labelP.getTextSize(),
     76                                  labelP);
     77                 for (size_t c = 0; c < SK_ARRAY_COUNT(kSolidColors); ++c) {
     78                     SkPaint modePaint;
     79                     modePaint.setXfermodeMode(mode);
     80                     modePaint.setColor(kSolidColors[c]);
     81                     modePaint.setStyle(kStrokes[s].fStyle);
     82                     modePaint.setStrokeWidth(kStrokes[s].fWidth);
     83 
     84                     this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempCanvas.get());
     85 
     86                     ++test;
     87                     x += kSize + 10;
     88                     if (!(test % kTestsPerRow)) {
     89                         x = 0;
     90                         y += kSize + 30;
     91                     }
     92                 }
     93                 for (size_t a = 0; a < SK_ARRAY_COUNT(kBmpAlphas); ++a) {
     94                     SkPaint modePaint;
     95                     modePaint.setXfermodeMode(mode);
     96                     modePaint.setAlpha(kBmpAlphas[a]);
     97                     modePaint.setShader(fBmpShader);
     98                     modePaint.setStyle(kStrokes[s].fStyle);
     99                     modePaint.setStrokeWidth(kStrokes[s].fWidth);
    100 
    101                     this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempCanvas.get());
    102 
    103                     ++test;
    104                     x += kSize + 10;
    105                     if (!(test % kTestsPerRow)) {
    106                         x = 0;
    107                         y += kSize + 30;
    108                     }
    109                 }
    110             }
    111         }
    112     }
    113 
    114 private:
    115     /**
    116      * GrContext has optimizations around full rendertarget draws that can be replaced with clears.
    117      * We are trying to test those. We could use saveLayer() to create small SkGpuDevices but
    118      * saveLayer() uses the texture cache. This means that the actual render target may be larger
    119      * than the layer. Because the clip will contain the layer's bounds, no draws will be full-RT.
    120      * So when running on a GPU canvas we explicitly create a temporary canvas using a texture with
    121      * dimensions exactly matching the layer size.
    122      */
    123     SkCanvas* possiblyCreateTempCanvas(SkCanvas* baseCanvas, int w, int h) {
    124         SkCanvas* tempCanvas = NULL;
    125 #if SK_SUPPORT_GPU
    126         GrRenderTarget* rt = baseCanvas->getDevice()->accessRenderTarget();
    127         if (NULL != rt) {
    128             GrContext* context = rt->getContext();
    129             GrTextureDesc desc;
    130             desc.fWidth = w;
    131             desc.fHeight = h;
    132             desc.fConfig = rt->config();
    133             desc.fFlags = kRenderTarget_GrTextureFlagBit;
    134             SkAutoTUnref<GrSurface> surface(context->createUncachedTexture(desc, NULL, 0));
    135             SkAutoTUnref<SkBaseDevice> device(SkGpuDevice::Create(surface.get()));
    136             if (NULL != device.get()) {
    137                 tempCanvas = SkNEW_ARGS(SkCanvas, (device.get()));
    138             }
    139         }
    140 #endif
    141         return tempCanvas;
    142     }
    143 
    144     void drawMode(SkCanvas* canvas,
    145                   int x, int y, int w, int h,
    146                   const SkPaint& modePaint, SkCanvas* layerCanvas) {
    147         canvas->save();
    148 
    149         canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
    150 
    151         SkRect r = SkRect::MakeWH(SkIntToScalar(w), SkIntToScalar(h));
    152 
    153         SkCanvas* modeCanvas;
    154         if (NULL == layerCanvas) {
    155             canvas->saveLayer(&r, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
    156             modeCanvas = canvas;
    157         } else {
    158             modeCanvas = layerCanvas;
    159         }
    160 
    161         SkPaint bgPaint;
    162         bgPaint.setAntiAlias(false);
    163         bgPaint.setShader(fBGShader);
    164         modeCanvas->drawRect(r, bgPaint);
    165         modeCanvas->drawRect(r, modePaint);
    166         modeCanvas = NULL;
    167 
    168         if (NULL == layerCanvas) {
    169             canvas->restore();
    170         } else {
    171             SkBitmap bitmap = layerCanvas->getDevice()->accessBitmap(false);
    172             canvas->drawBitmap(bitmap, 0, 0);
    173         }
    174 
    175         r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
    176         SkPaint borderPaint;
    177         borderPaint.setStyle(SkPaint::kStroke_Style);
    178         canvas->drawRect(r, borderPaint);
    179 
    180         canvas->restore();
    181     }
    182 
    183     virtual void onOnceBeforeDraw() SK_OVERRIDE {
    184         static const uint32_t kCheckData[] = {
    185             SkPackARGB32(0xFF, 0x40, 0x40, 0x40),
    186             SkPackARGB32(0xFF, 0xD0, 0xD0, 0xD0),
    187             SkPackARGB32(0xFF, 0xD0, 0xD0, 0xD0),
    188             SkPackARGB32(0xFF, 0x40, 0x40, 0x40)
    189         };
    190         SkBitmap bg;
    191         bg.setConfig(SkBitmap::kARGB_8888_Config, 2, 2, 0, kOpaque_SkAlphaType);
    192         bg.allocPixels();
    193         SkAutoLockPixels bgAlp(bg);
    194         memcpy(bg.getPixels(), kCheckData, sizeof(kCheckData));
    195 
    196         fBGShader.reset(SkShader::CreateBitmapShader(bg,
    197                                                      SkShader::kRepeat_TileMode,
    198                                                      SkShader::kRepeat_TileMode));
    199         SkMatrix lm;
    200         lm.setScale(SkIntToScalar(kCheckSize), SkIntToScalar(kCheckSize));
    201         fBGShader->setLocalMatrix(lm);
    202 
    203         SkPaint bmpPaint;
    204         static const SkPoint kCenter = { SkIntToScalar(kSize) / 2, SkIntToScalar(kSize) / 2 };
    205         static const SkColor kColors[] = { SK_ColorTRANSPARENT, 0x80800000,
    206                                           0xF020F060, SK_ColorWHITE };
    207         bmpPaint.setShader(SkGradientShader::CreateRadial(kCenter,
    208                                                           3 * SkIntToScalar(kSize) / 4,
    209                                                           kColors,
    210                                                           NULL,
    211                                                           SK_ARRAY_COUNT(kColors),
    212                                                           SkShader::kRepeat_TileMode))->unref();
    213 
    214         SkBitmap bmp;
    215         bmp.setConfig(SkBitmap::kARGB_8888_Config, kSize, kSize);
    216         bmp.allocPixels();
    217         SkCanvas bmpCanvas(bmp);
    218 
    219         bmpCanvas.clear(SK_ColorTRANSPARENT);
    220         SkRect rect = { SkIntToScalar(kSize) / 8, SkIntToScalar(kSize) / 8,
    221                         7 * SkIntToScalar(kSize) / 8, 7 * SkIntToScalar(kSize) / 8};
    222         bmpCanvas.drawRect(rect, bmpPaint);
    223 
    224         fBmpShader.reset(SkShader::CreateBitmapShader(bmp,
    225                                                       SkShader::kClamp_TileMode,
    226                                                       SkShader::kClamp_TileMode));
    227     }
    228 
    229     enum {
    230         kCheckSize = 8,
    231         kSize = 30,
    232         kTestsPerRow = 15,
    233     };
    234 
    235     SkAutoTUnref<SkShader> fBGShader;
    236     SkAutoTUnref<SkShader> fBmpShader;
    237 
    238     typedef GM INHERITED;
    239 };
    240 
    241 //////////////////////////////////////////////////////////////////////////////
    242 
    243 DEF_GM(return new Xfermodes3GM;)
    244 
    245 }
    246