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