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