Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2014 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 "SkGradientShader.h"
     11 #include "SkSurface.h"
     12 #include "SkSurfaceProps.h"
     13 
     14 #define W 200
     15 #define H 100
     16 
     17 static sk_sp<SkShader> make_shader() {
     18     int a = 0x99;
     19     int b = 0xBB;
     20     SkPoint pts[] = { { 0, 0 }, { W, H } };
     21     SkColor colors[] = { SkColorSetRGB(a, a, a), SkColorSetRGB(b, b, b) };
     22     return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kClamp_TileMode);
     23 }
     24 
     25 static sk_sp<SkSurface> make_surface(GrContext* ctx, const SkImageInfo& info, SkPixelGeometry geo) {
     26     SkSurfaceProps props(0, geo);
     27     if (ctx) {
     28         return SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info, 0, &props);
     29     } else {
     30         return SkSurface::MakeRaster(info, &props);
     31     }
     32 }
     33 
     34 static void test_draw(SkCanvas* canvas, const char label[]) {
     35     SkPaint paint;
     36 
     37     paint.setAntiAlias(true);
     38     paint.setLCDRenderText(true);
     39     paint.setDither(true);
     40 
     41     paint.setShader(make_shader());
     42     canvas->drawRect(SkRect::MakeWH(W, H), paint);
     43     paint.setShader(nullptr);
     44 
     45     paint.setColor(SK_ColorWHITE);
     46     paint.setTextSize(32);
     47     paint.setTextAlign(SkPaint::kCenter_Align);
     48     sk_tool_utils::set_portable_typeface(&paint);
     49     canvas->drawString(label, W / 2, H * 3 / 4, paint);
     50 }
     51 
     52 class SurfacePropsGM : public skiagm::GM {
     53 public:
     54     SurfacePropsGM() {}
     55 
     56 protected:
     57     SkString onShortName() override {
     58         return SkString("surfaceprops");
     59     }
     60 
     61     SkISize onISize() override {
     62         return SkISize::Make(W, H * 5);
     63     }
     64 
     65     void onDraw(SkCanvas* canvas) override {
     66         GrContext* ctx = canvas->getGrContext();
     67 
     68         // must be opaque to have a hope of testing LCD text
     69         const SkImageInfo info = SkImageInfo::MakeN32(W, H, kOpaque_SkAlphaType);
     70 
     71         const struct {
     72             SkPixelGeometry fGeo;
     73             const char*     fLabel;
     74         } recs[] = {
     75             { kUnknown_SkPixelGeometry, "Unknown" },
     76             { kRGB_H_SkPixelGeometry,   "RGB_H" },
     77             { kBGR_H_SkPixelGeometry,   "BGR_H" },
     78             { kRGB_V_SkPixelGeometry,   "RGB_V" },
     79             { kBGR_V_SkPixelGeometry,   "BGR_V" },
     80         };
     81 
     82         SkScalar x = 0;
     83         SkScalar y = 0;
     84         for (const auto& rec : recs) {
     85             auto surface(make_surface(ctx, info, rec.fGeo));
     86             if (!surface) {
     87                 SkDebugf("failed to create surface! label: %s", rec.fLabel);
     88                 continue;
     89             }
     90             test_draw(surface->getCanvas(), rec.fLabel);
     91             surface->draw(canvas, x, y, nullptr);
     92             y += H;
     93         }
     94     }
     95 
     96 private:
     97     typedef GM INHERITED;
     98 };
     99 DEF_GM( return new SurfacePropsGM )
    100 
    101 #ifdef SK_DEBUG
    102 static bool equal(const SkSurfaceProps& a, const SkSurfaceProps& b) {
    103     return a.flags() == b.flags() && a.pixelGeometry() == b.pixelGeometry();
    104 }
    105 #endif
    106 
    107 class NewSurfaceGM : public skiagm::GM {
    108 public:
    109     NewSurfaceGM() {}
    110 
    111 protected:
    112     SkString onShortName() override {
    113         return SkString("surfacenew");
    114     }
    115 
    116     SkISize onISize() override {
    117         return SkISize::Make(300, 140);
    118     }
    119 
    120     static void drawInto(SkCanvas* canvas) {
    121         canvas->drawColor(SK_ColorRED);
    122     }
    123 
    124     void onDraw(SkCanvas* canvas) override {
    125         SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
    126 
    127         auto surf(sk_tool_utils::makeSurface(canvas, info, nullptr));
    128         drawInto(surf->getCanvas());
    129 
    130         sk_sp<SkImage> image(surf->makeImageSnapshot());
    131         canvas->drawImage(image, 10, 10, nullptr);
    132 
    133         auto surf2(surf->makeSurface(info));
    134         drawInto(surf2->getCanvas());
    135 
    136         // Assert that the props were communicated transitively through the first image
    137         SkASSERT(equal(surf->props(), surf2->props()));
    138 
    139         sk_sp<SkImage> image2(surf2->makeImageSnapshot());
    140         canvas->drawImage(image2.get(), 10 + SkIntToScalar(image->width()) + 10, 10, nullptr);
    141     }
    142 
    143 private:
    144     typedef GM INHERITED;
    145 };
    146 DEF_GM( return new NewSurfaceGM )
    147 
    148 ///////////////////////////////////////////////////////////////////////////////////////////////////
    149 
    150 DEF_SIMPLE_GM(copy_on_write_retain, canvas, 256, 256) {
    151     const SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256);
    152     sk_sp<SkSurface> surf = sk_tool_utils::makeSurface(canvas, info);
    153 
    154     surf->getCanvas()->clear(SK_ColorRED);
    155     // its important that image survives longer than the next draw, so the surface will see
    156     // an outstanding image, and have to decide if it should retain or discard those pixels
    157     sk_sp<SkImage> image = surf->makeImageSnapshot();
    158 
    159     // normally a clear+opaque should trigger the discard optimization, but since we have a clip
    160     // it should not (we need the previous red pixels).
    161     surf->getCanvas()->clipRect(SkRect::MakeWH(128, 256));
    162     surf->getCanvas()->clear(SK_ColorBLUE);
    163 
    164     // expect to see two rects: blue | red
    165     canvas->drawImage(surf->makeImageSnapshot(), 0, 0, nullptr);
    166 }
    167 
    168 DEF_SIMPLE_GM(copy_on_write_savelayer, canvas, 256, 256) {
    169     const SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256);
    170     sk_sp<SkSurface> surf = sk_tool_utils::makeSurface(canvas, info);
    171     surf->getCanvas()->clear(SK_ColorRED);
    172     // its important that image survives longer than the next draw, so the surface will see
    173     // an outstanding image, and have to decide if it should retain or discard those pixels
    174     sk_sp<SkImage> image = surf->makeImageSnapshot();
    175 
    176     // now draw into a full-screen layer. This should (a) trigger a copy-on-write, but it should
    177     // not trigger discard, even tho its alpha (SK_ColorBLUE) is opaque, since it is in a layer
    178     // with a non-opaque paint.
    179     SkPaint paint;
    180     paint.setAlpha(0x40);
    181     surf->getCanvas()->saveLayer({0, 0, 256, 256}, &paint);
    182     surf->getCanvas()->clear(SK_ColorBLUE);
    183     surf->getCanvas()->restore();
    184 
    185     // expect to see two rects: blue blended on red
    186     canvas->drawImage(surf->makeImageSnapshot(), 0, 0, nullptr);
    187 }
    188