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 "sk_tool_utils.h"
     10 #include "SkBitmap.h"
     11 #include "SkGradientShader.h"
     12 #include "SkSurface.h"
     13 #include "SkBlendModePriv.h"
     14 #include "SkColorPriv.h"
     15 
     16 #if SK_SUPPORT_GPU
     17 #include "GrContext.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         constexpr SkColor kSolidColors[] = {
     53             SK_ColorTRANSPARENT,
     54             SK_ColorBLUE,
     55             0x80808000
     56         };
     57 
     58         constexpr SkColor kBmpAlphas[] = {
     59             0xff,
     60             0x80,
     61         };
     62 
     63         auto tempSurface(this->possiblyCreateTempSurface(canvas, kSize, kSize));
     64 
     65         int test = 0;
     66         int x = 0, y = 0;
     67         constexpr 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 <= (size_t)SkBlendMode::kLastMode; ++m) {
     73                 SkBlendMode mode = static_cast<SkBlendMode>(m);
     74                 canvas->drawString(SkBlendMode_Name(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.setBlendMode(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, tempSurface.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.setBlendMode(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, tempSurface.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     sk_sp<SkSurface> possiblyCreateTempSurface(SkCanvas* baseCanvas, int w, int h) {
    125 #if SK_SUPPORT_GPU
    126         GrContext* context = baseCanvas->getGrContext();
    127         SkImageInfo baseInfo = baseCanvas->imageInfo();
    128         SkImageInfo info = SkImageInfo::Make(w, h, baseInfo.colorType(), baseInfo.alphaType(),
    129                                              baseInfo.refColorSpace());
    130         SkSurfaceProps canvasProps(SkSurfaceProps::kLegacyFontHost_InitType);
    131         baseCanvas->getProps(&canvasProps);
    132         return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0, &canvasProps);
    133 #else
    134         return nullptr;
    135 #endif
    136     }
    137 
    138     void drawMode(SkCanvas* canvas,
    139                   int x, int y, int w, int h,
    140                   const SkPaint& modePaint, SkSurface* surface) {
    141         canvas->save();
    142         canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
    143 
    144         SkRect r = SkRect::MakeWH(SkIntToScalar(w), SkIntToScalar(h));
    145 
    146         SkCanvas* modeCanvas;
    147         if (nullptr == surface) {
    148             canvas->saveLayer(&r, nullptr);
    149             modeCanvas = canvas;
    150         } else {
    151             modeCanvas = surface->getCanvas();
    152         }
    153 
    154         SkPaint bgPaint;
    155         bgPaint.setAntiAlias(false);
    156         bgPaint.setShader(fBGShader);
    157         modeCanvas->drawRect(r, bgPaint);
    158         modeCanvas->drawRect(r, modePaint);
    159         modeCanvas = nullptr;
    160 
    161         if (nullptr == surface) {
    162             canvas->restore();
    163         } else {
    164             surface->draw(canvas, 0, 0, nullptr);
    165         }
    166 
    167         r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
    168         SkPaint borderPaint;
    169         borderPaint.setStyle(SkPaint::kStroke_Style);
    170         canvas->drawRect(r, borderPaint);
    171 
    172         canvas->restore();
    173     }
    174 
    175     void onOnceBeforeDraw() override {
    176         const uint32_t kCheckData[] = {
    177             SkPackARGB32(0xFF, 0x42, 0x41, 0x42),
    178             SkPackARGB32(0xFF, 0xD6, 0xD3, 0xD6),
    179             SkPackARGB32(0xFF, 0xD6, 0xD3, 0xD6),
    180             SkPackARGB32(0xFF, 0x42, 0x41, 0x42)
    181         };
    182         SkBitmap bg;
    183         bg.allocN32Pixels(2, 2, true);
    184         memcpy(bg.getPixels(), kCheckData, sizeof(kCheckData));
    185 
    186         SkMatrix lm;
    187         lm.setScale(SkIntToScalar(kCheckSize), SkIntToScalar(kCheckSize));
    188         fBGShader = SkShader::MakeBitmapShader(bg, SkShader::kRepeat_TileMode,
    189                                                SkShader::kRepeat_TileMode, &lm);
    190 
    191         SkPaint bmpPaint;
    192         const SkPoint kCenter = { SkIntToScalar(kSize) / 2, SkIntToScalar(kSize) / 2 };
    193         const SkColor kColors[] = {
    194             SK_ColorTRANSPARENT, 0x80800000, 0xF020F060, SK_ColorWHITE
    195         };
    196         bmpPaint.setShader(SkGradientShader::MakeRadial(kCenter, 3 * SkIntToScalar(kSize) / 4,
    197                                                         kColors, nullptr, SK_ARRAY_COUNT(kColors),
    198                                                         SkShader::kRepeat_TileMode));
    199 
    200         SkBitmap bmp;
    201         bmp.allocN32Pixels(kSize, kSize);
    202         SkCanvas bmpCanvas(bmp);
    203 
    204         bmpCanvas.clear(SK_ColorTRANSPARENT);
    205         SkRect rect = { SkIntToScalar(kSize) / 8, SkIntToScalar(kSize) / 8,
    206                         7 * SkIntToScalar(kSize) / 8, 7 * SkIntToScalar(kSize) / 8};
    207         bmpCanvas.drawRect(rect, bmpPaint);
    208 
    209         fBmpShader = SkShader::MakeBitmapShader(bmp, SkShader::kClamp_TileMode,
    210                                                 SkShader::kClamp_TileMode);
    211     }
    212 
    213     enum {
    214         kCheckSize = 8,
    215         kSize = 30,
    216         kTestsPerRow = 15,
    217     };
    218 
    219     sk_sp<SkShader> fBGShader;
    220     sk_sp<SkShader> fBmpShader;
    221 
    222     typedef GM INHERITED;
    223 };
    224 
    225 //////////////////////////////////////////////////////////////////////////////
    226 
    227 DEF_GM(return new Xfermodes3GM;)
    228 
    229 }
    230