Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2012 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 
     10 #include "SkCanvas.h"
     11 #include "SkGradientShader.h"
     12 #include "SkGraphics.h"
     13 #include "SkImage.h"
     14 #include "SkShader.h"
     15 #include "SkString.h"
     16 #include "SkTDArray.h"
     17 
     18 static sk_sp<SkShader> make_shader(SkBlendMode mode) {
     19     SkPoint pts[2];
     20     SkColor colors[2];
     21 
     22     pts[0].set(0, 0);
     23     pts[1].set(SkIntToScalar(100), 0);
     24     colors[0] = SK_ColorRED;
     25     colors[1] = SK_ColorBLUE;
     26     auto shaderA = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kClamp_TileMode);
     27 
     28     pts[0].set(0, 0);
     29     pts[1].set(0, SkIntToScalar(100));
     30     colors[0] = SK_ColorBLACK;
     31     colors[1] = SkColorSetARGB(0x80, 0, 0, 0);
     32     auto shaderB = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kClamp_TileMode);
     33 
     34     return SkShader::MakeComposeShader(std::move(shaderA), std::move(shaderB), mode);
     35 }
     36 
     37 class ComposeShaderGM : public skiagm::GM {
     38 public:
     39     ComposeShaderGM() {
     40         fShader = make_shader(SkBlendMode::kDstIn);
     41     }
     42 
     43 protected:
     44     SkString onShortName() override {
     45         return SkString("composeshader");
     46     }
     47 
     48     SkISize onISize() override {
     49         return SkISize::Make(120, 120);
     50     }
     51 
     52     void onDraw(SkCanvas* canvas) override {
     53         SkPaint paint;
     54         paint.setColor(SK_ColorGREEN);
     55         canvas->drawRect(SkRect::MakeWH(100, 100), paint);
     56         paint.setShader(fShader);
     57         canvas->drawRect(SkRect::MakeWH(100, 100), paint);
     58     }
     59 
     60 protected:
     61     sk_sp<SkShader> fShader;
     62 
     63 private:
     64     typedef GM INHERITED ;
     65 };
     66 
     67 class ComposeShaderAlphaGM : public skiagm::GM {
     68 public:
     69     ComposeShaderAlphaGM() {}
     70 
     71 protected:
     72     SkString onShortName() override {
     73         return SkString("composeshader_alpha");
     74     }
     75 
     76     SkISize onISize() override {
     77         return SkISize::Make(750, 220);
     78     }
     79 
     80     void onDraw(SkCanvas* canvas) override {
     81         sk_sp<SkShader> shaders[] = {
     82             make_shader(SkBlendMode::kDstIn),
     83             make_shader(SkBlendMode::kSrcOver),
     84         };
     85 
     86         SkPaint paint;
     87         paint.setColor(SK_ColorGREEN);
     88 
     89         const SkRect r = SkRect::MakeXYWH(5, 5, 100, 100);
     90 
     91         for (size_t y = 0; y < SK_ARRAY_COUNT(shaders); ++y) {
     92             canvas->save();
     93             for (int alpha = 0xFF; alpha > 0; alpha -= 0x28) {
     94                 paint.setAlpha(0xFF);
     95                 paint.setShader(nullptr);
     96                 canvas->drawRect(r, paint);
     97 
     98                 paint.setAlpha(alpha);
     99                 paint.setShader(shaders[y]);
    100                 canvas->drawRect(r, paint);
    101 
    102                 canvas->translate(r.width() + 5, 0);
    103             }
    104             canvas->restore();
    105             canvas->translate(0, r.height() + 5);
    106         }
    107     }
    108 
    109 private:
    110     typedef GM INHERITED ;
    111 };
    112 
    113 
    114 // creates a square bitmap with red background and a green circle in the center
    115 static void draw_color_bm(SkBitmap* bm, int length) {
    116     SkPaint paint;
    117     paint.setColor(SK_ColorGREEN);
    118 
    119     bm->allocN32Pixels(length, length);
    120     bm->eraseColor(SK_ColorRED);
    121 
    122     SkCanvas canvas(*bm);
    123     canvas.drawCircle(SkIntToScalar(length/2), SkIntToScalar(length/2), SkIntToScalar(length/2),
    124                       paint);
    125 }
    126 
    127 // creates a square alpha8 bitmap with transparent background and an opaque circle in the center
    128 static void draw_alpha8_bm(SkBitmap* bm, int length) {
    129     SkPaint circlePaint;
    130     circlePaint.setColor(SK_ColorBLACK);
    131 
    132     bm->allocPixels(SkImageInfo::MakeA8(length, length));
    133     bm->eraseColor(SK_ColorTRANSPARENT);
    134 
    135     SkCanvas canvas(*bm);
    136     canvas.drawCircle(SkIntToScalar(length/2), SkIntToScalar(length/2), SkIntToScalar(length/4),
    137                       circlePaint);
    138 }
    139 
    140 // creates a linear gradient shader
    141 static sk_sp<SkShader> make_linear_gradient_shader(int length) {
    142     SkPoint pts[2];
    143     SkColor colors[2];
    144     pts[0].set(0, 0);
    145     pts[1].set(SkIntToScalar(length), 0);
    146     colors[0] = SK_ColorBLUE;
    147     colors[1] = SkColorSetARGB(0, 0, 0, 0xFF);
    148     return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kClamp_TileMode);
    149 }
    150 
    151 
    152 class ComposeShaderBitmapGM : public skiagm::GM {
    153 public:
    154     ComposeShaderBitmapGM() {}
    155 
    156 protected:
    157     void onOnceBeforeDraw() override {
    158         draw_color_bm(&fColorBitmap, squareLength);
    159         draw_alpha8_bm(&fAlpha8Bitmap, squareLength);
    160         SkMatrix s;
    161         s.reset();
    162         fColorBitmapShader = SkShader::MakeBitmapShader(fColorBitmap, SkShader::kRepeat_TileMode,
    163                                                         SkShader::kRepeat_TileMode, &s);
    164         fAlpha8BitmapShader = SkShader::MakeBitmapShader(fAlpha8Bitmap, SkShader::kRepeat_TileMode,
    165                                                          SkShader::kRepeat_TileMode, &s);
    166         fLinearGradientShader = make_linear_gradient_shader(squareLength);
    167     }
    168 
    169     SkString onShortName() override {
    170         return SkString("composeshader_bitmap");
    171     }
    172 
    173     SkISize onISize() override {
    174         return SkISize::Make(7 * (squareLength + 5), 2 * (squareLength + 5));
    175     }
    176 
    177     void onDraw(SkCanvas* canvas) override {
    178         SkBlendMode mode = SkBlendMode::kDstOver;
    179 
    180         sk_sp<SkShader> shaders[] = {
    181             // gradient should appear over color bitmap
    182             SkShader::MakeComposeShader(fLinearGradientShader, fColorBitmapShader, mode),
    183             // gradient should appear over alpha8 bitmap colorized by the paint color
    184             SkShader::MakeComposeShader(fLinearGradientShader, fAlpha8BitmapShader, mode),
    185         };
    186 
    187         SkPaint paint;
    188         paint.setColor(SK_ColorYELLOW);
    189 
    190         const SkRect r = SkRect::MakeXYWH(0, 0, SkIntToScalar(squareLength),
    191                                           SkIntToScalar(squareLength));
    192 
    193         for (size_t y = 0; y < SK_ARRAY_COUNT(shaders); ++y) {
    194             canvas->save();
    195             for (int alpha = 0xFF; alpha > 0; alpha -= 0x28) {
    196                 paint.setAlpha(alpha);
    197                 paint.setShader(shaders[y]);
    198                 canvas->drawRect(r, paint);
    199 
    200                 canvas->translate(r.width() + 5, 0);
    201             }
    202             canvas->restore();
    203             canvas->translate(0, r.height() + 5);
    204         }
    205     }
    206 
    207 private:
    208     /** This determines the length and width of the bitmaps used in the ComposeShaders.  Values
    209      *  above 20 may cause an SkASSERT to fail in SkSmallAllocator. However, larger values will
    210      *  work in a release build.  You can change this parameter and then compile a release build
    211      *  to have this GM draw larger bitmaps for easier visual inspection.
    212      */
    213     static constexpr int squareLength = 20;
    214 
    215     SkBitmap fColorBitmap;
    216     SkBitmap fAlpha8Bitmap;
    217     sk_sp<SkShader> fColorBitmapShader;
    218     sk_sp<SkShader> fAlpha8BitmapShader;
    219     sk_sp<SkShader> fLinearGradientShader;
    220 
    221     typedef GM INHERITED;
    222 };
    223 
    224 DEF_SIMPLE_GM(composeshader_bitmap2, canvas, 200, 200) {
    225     int width = 255;
    226     int height = 255;
    227     SkTDArray<uint8_t> dst8Storage;
    228     dst8Storage.setCount(width * height);
    229     SkTDArray<uint32_t> dst32Storage;
    230     dst32Storage.setCount(width * height * sizeof(int32_t));
    231     for (int y = 0; y < height; ++y) {
    232         for (int x = 0; x < width; ++x) {
    233             dst8Storage[y * width + x] = (y + x) / 2;
    234             dst32Storage[y * width + x] = SkPackARGB32(0xFF, x, y, 0);
    235         }
    236     }
    237     SkPaint paint;
    238     paint.setAntiAlias(true);
    239     paint.setColor(SK_ColorBLUE);
    240     SkRect r = {0, 0, SkIntToScalar(width), SkIntToScalar(height)};
    241     canvas->drawRect(r, paint);
    242     SkBitmap skBitmap, skMask;
    243     SkImageInfo imageInfo = SkImageInfo::Make(width, height,
    244             SkColorType::kN32_SkColorType, kPremul_SkAlphaType);
    245     skBitmap.installPixels(imageInfo, dst32Storage.begin(), width * sizeof(int32_t),
    246                            nullptr, nullptr);
    247     imageInfo = SkImageInfo::Make(width, height,
    248             SkColorType::kAlpha_8_SkColorType, kPremul_SkAlphaType);
    249     skMask.installPixels(imageInfo, dst8Storage.begin(), width, nullptr, nullptr);
    250     sk_sp<SkImage> skSrc = SkImage::MakeFromBitmap(skBitmap);
    251     sk_sp<SkImage> skMaskImage = SkImage::MakeFromBitmap(skMask);
    252     paint.setShader(
    253         SkShader::MakeComposeShader(skMaskImage->makeShader(), skSrc->makeShader(),
    254                                     SkBlendMode::kSrcIn));
    255     canvas->drawRect(r, paint);
    256 }
    257 
    258 //////////////////////////////////////////////////////////////////////////////
    259 
    260 DEF_GM( return new ComposeShaderGM; )
    261 DEF_GM( return new ComposeShaderAlphaGM; )
    262 DEF_GM( return new ComposeShaderBitmapGM; )
    263