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