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, 620);
     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         for (size_t m = 0; m <= SkXfermode::kLastMode; ++m) {
     66             SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(m);
     67             canvas->drawText(SkXfermode::ModeName(mode),
     68                              strlen(SkXfermode::ModeName(mode)),
     69                              SkIntToScalar(x),
     70                              SkIntToScalar(y + kSize + 3) + labelP.getTextSize(),
     71                              labelP);
     72             for (size_t c = 0; c < SK_ARRAY_COUNT(kSolidColors); ++c) {
     73                 SkPaint modePaint;
     74                 modePaint.setXfermodeMode(mode);
     75                 modePaint.setColor(kSolidColors[c]);
     76 
     77                 this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempCanvas.get());
     78 
     79                 ++test;
     80                 x += kSize + 10;
     81                 if (!(test % kTestsPerRow)) {
     82                     x = 0;
     83                     y += kSize + 30;
     84                 }
     85             }
     86             for (size_t a = 0; a < SK_ARRAY_COUNT(kBmpAlphas); ++a) {
     87                 SkPaint modePaint;
     88                 modePaint.setXfermodeMode(mode);
     89                 modePaint.setAlpha(kBmpAlphas[a]);
     90                 modePaint.setShader(fBmpShader);
     91 
     92                 this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempCanvas.get());
     93 
     94                 ++test;
     95                 x += kSize + 10;
     96                 if (!(test % kTestsPerRow)) {
     97                     x = 0;
     98                     y += kSize + 30;
     99                 }
    100             }
    101         }
    102     }
    103 
    104 private:
    105     /**
    106      * GrContext has optimizations around full rendertarget draws that can be replaced with clears.
    107      * We are trying to test those. We could use saveLayer() to create small SkGpuDevices but
    108      * saveLayer() uses the texture cache. This means that the actual render target may be larger
    109      * than the layer. Because the clip will contain the layer's bounds, no draws will be full-RT.
    110      * So when running on a GPU canvas we explicitly create a temporary canvas using a texture with
    111      * dimensions exactly matching the layer size.
    112      */
    113     SkCanvas* possiblyCreateTempCanvas(SkCanvas* baseCanvas, int w, int h) {
    114         SkCanvas* tempCanvas = NULL;
    115 #if SK_SUPPORT_GPU
    116         GrRenderTarget* rt = baseCanvas->getDevice()->accessRenderTarget();
    117         if (NULL != rt) {
    118             GrContext* context = rt->getContext();
    119             GrTextureDesc desc;
    120             desc.fWidth = w;
    121             desc.fHeight = h;
    122             desc.fConfig = rt->config();
    123             desc.fFlags = kRenderTarget_GrTextureFlagBit;
    124             SkAutoTUnref<GrSurface> surface(context->createUncachedTexture(desc, NULL, 0));
    125             SkAutoTUnref<SkDevice> device(SkGpuDevice::Create(surface.get()));
    126             if (NULL != device.get()) {
    127                 tempCanvas = SkNEW_ARGS(SkCanvas, (device.get()));
    128             }
    129         }
    130 #endif
    131         return tempCanvas;
    132     }
    133 
    134     void drawMode(SkCanvas* canvas,
    135                   int x, int y, int w, int h,
    136                   const SkPaint& modePaint, SkCanvas* layerCanvas) {
    137         canvas->save();
    138 
    139         canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
    140 
    141         SkRect r = SkRect::MakeWH(SkIntToScalar(w), SkIntToScalar(h));
    142 
    143         SkCanvas* modeCanvas;
    144         if (NULL == layerCanvas) {
    145             canvas->saveLayer(&r, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
    146             modeCanvas = canvas;
    147         } else {
    148             modeCanvas = layerCanvas;
    149         }
    150 
    151         SkPaint bgPaint;
    152         bgPaint.setAntiAlias(false);
    153         bgPaint.setShader(fBGShader);
    154         modeCanvas->drawRect(r, bgPaint);
    155         modeCanvas->drawRect(r, modePaint);
    156         modeCanvas = NULL;
    157 
    158         if (NULL == layerCanvas) {
    159             canvas->restore();
    160         } else {
    161             SkBitmap bitmap = layerCanvas->getDevice()->accessBitmap(false);
    162             canvas->drawBitmap(bitmap, 0, 0);
    163         }
    164 
    165         r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
    166         SkPaint borderPaint;
    167         borderPaint.setStyle(SkPaint::kStroke_Style);
    168         canvas->drawRect(r, borderPaint);
    169 
    170         canvas->restore();
    171     }
    172 
    173     virtual void onOnceBeforeDraw() SK_OVERRIDE {
    174         static const uint32_t kCheckData[] = {
    175             SkPackARGB32(0xFF, 0x40, 0x40, 0x40),
    176             SkPackARGB32(0xFF, 0xD0, 0xD0, 0xD0),
    177             SkPackARGB32(0xFF, 0xD0, 0xD0, 0xD0),
    178             SkPackARGB32(0xFF, 0x40, 0x40, 0x40)
    179         };
    180         SkBitmap bg;
    181         bg.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
    182         bg.allocPixels();
    183         SkAutoLockPixels bgAlp(bg);
    184         memcpy(bg.getPixels(), kCheckData, sizeof(kCheckData));
    185         bg.setIsOpaque(true);
    186 
    187         fBGShader.reset(SkShader::CreateBitmapShader(bg,
    188                                                      SkShader::kRepeat_TileMode,
    189                                                      SkShader::kRepeat_TileMode));
    190         SkMatrix lm;
    191         lm.setScale(SkIntToScalar(kCheckSize), SkIntToScalar(kCheckSize));
    192         fBGShader->setLocalMatrix(lm);
    193 
    194         SkPaint bmpPaint;
    195         static const SkPoint kCenter = { SkIntToScalar(kSize) / 2, SkIntToScalar(kSize) / 2 };
    196         static const SkColor kColors[] = { SK_ColorTRANSPARENT, 0x80800000,
    197                                           0xF020F060, SK_ColorWHITE };
    198         bmpPaint.setShader(SkGradientShader::CreateRadial(kCenter,
    199                                                           3 * SkIntToScalar(kSize) / 4,
    200                                                           kColors,
    201                                                           NULL,
    202                                                           SK_ARRAY_COUNT(kColors),
    203                                                           SkShader::kRepeat_TileMode))->unref();
    204 
    205         SkBitmap bmp;
    206         bmp.setConfig(SkBitmap::kARGB_8888_Config, kSize, kSize);
    207         bmp.allocPixels();
    208         SkCanvas bmpCanvas(bmp);
    209 
    210         bmpCanvas.clear(SK_ColorTRANSPARENT);
    211         SkRect rect = { SkIntToScalar(kSize) / 8, SkIntToScalar(kSize) / 8,
    212                         7 * SkIntToScalar(kSize) / 8, 7 * SkIntToScalar(kSize) / 8};
    213         bmpCanvas.drawRect(rect, bmpPaint);
    214 
    215         fBmpShader.reset(SkShader::CreateBitmapShader(bmp,
    216                                                       SkShader::kClamp_TileMode,
    217                                                       SkShader::kClamp_TileMode));
    218     }
    219 
    220     enum {
    221         kCheckSize = 8,
    222         kSize = 30,
    223         kTestsPerRow = 15,
    224     };
    225 
    226     SkAutoTUnref<SkShader> fBGShader;
    227     SkAutoTUnref<SkShader> fBmpShader;
    228 
    229     typedef GM INHERITED;
    230 };
    231 
    232 //////////////////////////////////////////////////////////////////////////////
    233 
    234 DEF_GM(return new Xfermodes3GM;)
    235 
    236 }
    237