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 #include "SkTextUtils.h" 14 15 #define W 200 16 #define H 100 17 18 static sk_sp<SkShader> make_shader() { 19 int a = 0x99; 20 int b = 0xBB; 21 SkPoint pts[] = { { 0, 0 }, { W, H } }; 22 SkColor colors[] = { SkColorSetRGB(a, a, a), SkColorSetRGB(b, b, b) }; 23 return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kClamp_TileMode); 24 } 25 26 static sk_sp<SkSurface> make_surface(GrContext* ctx, const SkImageInfo& info, SkPixelGeometry geo) { 27 SkSurfaceProps props(0, geo); 28 if (ctx) { 29 return SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info, 0, &props); 30 } else { 31 return SkSurface::MakeRaster(info, &props); 32 } 33 } 34 35 static void test_draw(SkCanvas* canvas, const char label[]) { 36 SkPaint paint; 37 38 paint.setAntiAlias(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 SkFont font(sk_tool_utils::create_portable_typeface(), 32); 47 font.setEdging(SkFont::Edging::kSubpixelAntiAlias); 48 SkTextUtils::DrawString(canvas, label, W / 2, H * 3 / 4, font, paint, 49 SkTextUtils::kCenter_Align); 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.setAlphaf(0.25f); 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 189 DEF_SIMPLE_GM(surface_underdraw, canvas, 256, 256) { 190 SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256, nullptr); 191 auto surf = sk_tool_utils::makeSurface(canvas, info); 192 193 const SkIRect subset = SkIRect::MakeLTRB(180, 0, 256, 256); 194 195 // noisy background 196 { 197 SkPoint pts[] = {{0, 0}, {40, 50}}; 198 SkColor colors[] = {SK_ColorRED, SK_ColorBLUE}; 199 auto sh = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kRepeat_TileMode); 200 SkPaint paint; 201 paint.setShader(sh); 202 surf->getCanvas()->drawPaint(paint); 203 } 204 205 // save away the right-hand strip, then clear it 206 sk_sp<SkImage> saveImg = surf->makeImageSnapshot(subset); 207 { 208 SkPaint paint; 209 paint.setBlendMode(SkBlendMode::kClear); 210 surf->getCanvas()->drawRect(SkRect::Make(subset), paint); 211 } 212 213 // draw the "foreground" 214 { 215 SkPaint paint; 216 paint.setColor(SK_ColorGREEN); 217 SkRect r = { 0, 10, 256, 35 }; 218 while (r.fBottom < 256) { 219 surf->getCanvas()->drawRect(r, paint); 220 r.offset(0, r.height() * 2); 221 } 222 } 223 224 // apply the "fade" 225 { 226 SkPoint pts[] = {{SkIntToScalar(subset.left()), 0}, {SkIntToScalar(subset.right()), 0}}; 227 SkColor colors[] = {0xFF000000, 0}; 228 auto sh = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kClamp_TileMode); 229 SkPaint paint; 230 paint.setShader(sh); 231 paint.setBlendMode(SkBlendMode::kDstIn); 232 surf->getCanvas()->drawRect(SkRect::Make(subset), paint); 233 } 234 235 // restore the original strip, drawing it "under" the current foreground 236 { 237 SkPaint paint; 238 paint.setBlendMode(SkBlendMode::kDstOver); 239 surf->getCanvas()->drawImage(saveImg, 240 SkIntToScalar(subset.left()), SkIntToScalar(subset.top()), 241 &paint); 242 } 243 244 // show it on screen 245 surf->draw(canvas, 0, 0, nullptr); 246 } 247