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 SkISize::Make(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);
    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             SkAutoROCanvasPixels ropixels(layerCanvas);
    172             SkBitmap bitmap;
    173             if (ropixels.asROBitmap(&bitmap)) {
    174                 canvas->drawBitmap(bitmap, 0, 0);
    175             }
    176         }
    177 
    178         r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
    179         SkPaint borderPaint;
    180         borderPaint.setStyle(SkPaint::kStroke_Style);
    181         canvas->drawRect(r, borderPaint);
    182 
    183         canvas->restore();
    184     }
    185 
    186     virtual void onOnceBeforeDraw() SK_OVERRIDE {
    187         static const uint32_t kCheckData[] = {
    188             SkPackARGB32(0xFF, 0x40, 0x40, 0x40),
    189             SkPackARGB32(0xFF, 0xD0, 0xD0, 0xD0),
    190             SkPackARGB32(0xFF, 0xD0, 0xD0, 0xD0),
    191             SkPackARGB32(0xFF, 0x40, 0x40, 0x40)
    192         };
    193         SkBitmap bg;
    194         bg.allocN32Pixels(2, 2, true);
    195         SkAutoLockPixels bgAlp(bg);
    196         memcpy(bg.getPixels(), kCheckData, sizeof(kCheckData));
    197 
    198         SkMatrix lm;
    199         lm.setScale(SkIntToScalar(kCheckSize), SkIntToScalar(kCheckSize));
    200         fBGShader.reset(SkShader::CreateBitmapShader(bg,
    201                                                      SkShader::kRepeat_TileMode,
    202                                                      SkShader::kRepeat_TileMode,
    203                                                      &lm));
    204 
    205         SkPaint bmpPaint;
    206         static const SkPoint kCenter = { SkIntToScalar(kSize) / 2, SkIntToScalar(kSize) / 2 };
    207         static const SkColor kColors[] = { SK_ColorTRANSPARENT, 0x80800000,
    208                                           0xF020F060, SK_ColorWHITE };
    209         bmpPaint.setShader(SkGradientShader::CreateRadial(kCenter,
    210                                                           3 * SkIntToScalar(kSize) / 4,
    211                                                           kColors,
    212                                                           NULL,
    213                                                           SK_ARRAY_COUNT(kColors),
    214                                                           SkShader::kRepeat_TileMode))->unref();
    215 
    216         SkBitmap bmp;
    217         bmp.allocN32Pixels(kSize, kSize);
    218         SkCanvas bmpCanvas(bmp);
    219 
    220         bmpCanvas.clear(SK_ColorTRANSPARENT);
    221         SkRect rect = { SkIntToScalar(kSize) / 8, SkIntToScalar(kSize) / 8,
    222                         7 * SkIntToScalar(kSize) / 8, 7 * SkIntToScalar(kSize) / 8};
    223         bmpCanvas.drawRect(rect, bmpPaint);
    224 
    225         fBmpShader.reset(SkShader::CreateBitmapShader(bmp,
    226                                                       SkShader::kClamp_TileMode,
    227                                                       SkShader::kClamp_TileMode));
    228     }
    229 
    230     enum {
    231         kCheckSize = 8,
    232         kSize = 30,
    233         kTestsPerRow = 15,
    234     };
    235 
    236     SkAutoTUnref<SkShader> fBGShader;
    237     SkAutoTUnref<SkShader> fBmpShader;
    238 
    239     typedef GM INHERITED;
    240 };
    241 
    242 //////////////////////////////////////////////////////////////////////////////
    243 
    244 DEF_GM(return new Xfermodes3GM;)
    245 
    246 }
    247