blob: 8ffefc97889fb96384cc7e9df3cdef7def2a02fc [file] [log] [blame]
robertphillips@google.comaaa9b292013-07-25 21:34:00 +00001/*
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"
robertphillips@google.comb7061172013-09-06 14:16:12 +00009#include "SkBlurMask.h"
robertphillips@google.com2cc0b472013-08-20 16:51:20 +000010#include "SkBlurMaskFilter.h"
robertphillips@google.comb7061172013-09-06 14:16:12 +000011#include "SkCanvas.h"
bsalomon9003d1e2015-10-23 11:13:01 -070012#include "SkGradientShader.h"
reeda5517e22015-07-14 10:54:12 -070013#include "SkImage.h"
bsalomon9c586542015-11-02 12:33:21 -080014#include "SkUtils.h"
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000015
16#if SK_SUPPORT_GPU
17#include "GrContext.h"
bsalomon4ee6bd82015-05-27 13:23:23 -070018#include "GrContextOptions.h"
bsalomon9c586542015-11-02 12:33:21 -080019#include "SkGr.h"
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000020#endif
21
bsalomon5c1262d2015-11-09 10:06:06 -080022/** Holds either a bitmap or image to be rendered and a rect that indicates what part of the bitmap
23 or image should be tested by the GM. The area outside of the rect is present to check
24 for bleed due to filtering/blurring. */
25struct TestPixels {
26 enum Type {
27 kBitmap,
28 kImage
29 };
reed9ce9d672016-03-17 10:51:11 -070030 Type fType;
31 SkBitmap fBitmap;
32 sk_sp<SkImage> fImage;
33 SkIRect fRect; // The region of the bitmap/image that should be rendered.
bsalomon5c1262d2015-11-09 10:06:06 -080034};
reeda5517e22015-07-14 10:54:12 -070035
bsalomon5c1262d2015-11-09 10:06:06 -080036/** Creates a bitmap with two one-pixel rings around a checkerboard. The checkerboard is 2x2
37 logically where each check has as many pixels as is necessary to fill the interior. The rect
38 to draw is set to the checkerboard portion. */
39template<typename PIXEL_TYPE>
bsalomona2e08372016-07-13 14:50:17 -070040bool make_ringed_bitmap(TestPixels* result, int width, int height,
bsalomon5c1262d2015-11-09 10:06:06 -080041 SkColorType ct, SkAlphaType at,
42 PIXEL_TYPE outerRingColor, PIXEL_TYPE innerRingColor,
43 PIXEL_TYPE checkColor1, PIXEL_TYPE checkColor2) {
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +000044 SkASSERT(0 == width % 2 && 0 == height % 2);
bsalomon5c1262d2015-11-09 10:06:06 -080045 SkASSERT(width >= 6 && height >= 6);
skia.committer@gmail.comed000842013-11-09 07:02:23 +000046
bsalomon5c1262d2015-11-09 10:06:06 -080047 result->fType = TestPixels::kBitmap;
48 SkImageInfo info = SkImageInfo::Make(width, height, ct, at);
49 size_t rowBytes = SkAlign4(info.minRowBytes());
50 result->fBitmap.allocPixels(info, rowBytes);
51
52 PIXEL_TYPE* scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, 0);
53 for (int x = 0; x < width; ++x) {
54 scanline[x] = outerRingColor;
55 }
56 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, 1);
57 scanline[0] = outerRingColor;
58 for (int x = 1; x < width - 1; ++x) {
59 scanline[x] = innerRingColor;
60 }
61 scanline[width - 1] = outerRingColor;
62
63 for (int y = 2; y < height / 2; ++y) {
64 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, y);
65 scanline[0] = outerRingColor;
66 scanline[1] = innerRingColor;
67 for (int x = 2; x < width / 2; ++x) {
68 scanline[x] = checkColor1;
69 }
70 for (int x = width / 2; x < width - 2; ++x) {
71 scanline[x] = checkColor2;
72 }
73 scanline[width - 2] = innerRingColor;
74 scanline[width - 1] = outerRingColor;
75 }
76
77 for (int y = height / 2; y < height - 2; ++y) {
78 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, y);
79 scanline[0] = outerRingColor;
80 scanline[1] = innerRingColor;
81 for (int x = 2; x < width / 2; ++x) {
82 scanline[x] = checkColor2;
83 }
84 for (int x = width / 2; x < width - 2; ++x) {
85 scanline[x] = checkColor1;
86 }
87 scanline[width - 2] = innerRingColor;
88 scanline[width - 1] = outerRingColor;
89 }
90
91 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, height - 2);
92 scanline[0] = outerRingColor;
93 for (int x = 1; x < width - 1; ++x) {
94 scanline[x] = innerRingColor;
95 }
96 scanline[width - 1] = outerRingColor;
97
98 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, height - 1);
99 for (int x = 0; x < width; ++x) {
100 scanline[x] = outerRingColor;
101 }
102 result->fBitmap.setImmutable();
103 result->fRect.set(2, 2, width - 2, height - 2);
104 return true;
105}
106
bsalomona2e08372016-07-13 14:50:17 -0700107/** Create a black and white checked bitmap with 2 1-pixel rings around the outside edge.
bsalomon5c1262d2015-11-09 10:06:06 -0800108 The inner ring is red and the outer ring is blue. */
bsalomona2e08372016-07-13 14:50:17 -0700109static bool make_ringed_color_bitmap(TestPixels* result, int width, int height) {
mtkleindbfd7ab2016-09-01 11:24:54 -0700110 const SkPMColor kBlue = SkPreMultiplyColor(SK_ColorBLUE);
111 const SkPMColor kRed = SkPreMultiplyColor(SK_ColorRED);
112 const SkPMColor kBlack = SkPreMultiplyColor(SK_ColorBLACK);
113 const SkPMColor kWhite = SkPreMultiplyColor(SK_ColorWHITE);
bsalomon48b24612016-08-25 06:45:29 -0700114 return make_ringed_bitmap<SkPMColor>(result, width, height, kN32_SkColorType,
bsalomon5c1262d2015-11-09 10:06:06 -0800115 kPremul_SkAlphaType, kBlue, kRed, kBlack, kWhite);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000116}
117
bsalomondf85a722015-11-04 04:23:45 -0800118/** Makes a alpha bitmap with 1 wide rect/ring of 0s, an inset of 1s, and the interior is a 2x2
bsalomon9003d1e2015-10-23 11:13:01 -0700119 checker board of 3/4 and 1/2. The inner checkers are large enough to fill the interior with
120 the 2x2 checker grid. */
bsalomona2e08372016-07-13 14:50:17 -0700121static bool make_ringed_alpha_bitmap(TestPixels* result, int width, int height) {
mtkleindbfd7ab2016-09-01 11:24:54 -0700122 constexpr uint8_t kZero = 0x00;
123 constexpr uint8_t kHalf = 0x80;
124 constexpr uint8_t k3Q = 0xC0;
125 constexpr uint8_t kOne = 0xFF;
bsalomona2e08372016-07-13 14:50:17 -0700126 return make_ringed_bitmap<uint8_t>(result, width, height, kAlpha_8_SkColorType,
bsalomon5c1262d2015-11-09 10:06:06 -0800127 kPremul_SkAlphaType, kZero, kOne, k3Q, kHalf);
128}
129
130/** Helper to reuse above functions to produce images rather than bmps */
131static void bmp_to_image(TestPixels* result) {
132 SkASSERT(TestPixels::kBitmap == result->fType);
reed9ce9d672016-03-17 10:51:11 -0700133 result->fImage = SkImage::MakeFromBitmap(result->fBitmap);
bsalomon5c1262d2015-11-09 10:06:06 -0800134 SkASSERT(result->fImage);
135 result->fType = TestPixels::kImage;
136 result->fBitmap.reset();
137}
138
139/** Color image case. */
bsalomona2e08372016-07-13 14:50:17 -0700140bool make_ringed_color_image(TestPixels* result, int width, int height) {
141 if (make_ringed_color_bitmap(result, width, height)) {
bsalomon5c1262d2015-11-09 10:06:06 -0800142 bmp_to_image(result);
143 return true;
144 }
145 return false;
146}
147
148/** Alpha image case. */
bsalomona2e08372016-07-13 14:50:17 -0700149bool make_ringed_alpha_image(TestPixels* result, int width, int height) {
150 if (make_ringed_alpha_bitmap(result, width, height)) {
bsalomon5c1262d2015-11-09 10:06:06 -0800151 bmp_to_image(result);
152 return true;
153 }
154 return false;
155}
156
reed2ad1aa62016-03-09 09:50:50 -0800157static sk_sp<SkShader> make_shader() {
mtkleindbfd7ab2016-09-01 11:24:54 -0700158 constexpr SkPoint pts[] = { {0, 0}, {20, 20} };
159 constexpr SkColor colors[] = { SK_ColorGREEN, SK_ColorYELLOW };
reed2ad1aa62016-03-09 09:50:50 -0800160 return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kMirror_TileMode);
bsalomon9003d1e2015-10-23 11:13:01 -0700161}
162
reed2ad1aa62016-03-09 09:50:50 -0800163static sk_sp<SkShader> make_null_shader() { return nullptr; }
bsalomon9003d1e2015-10-23 11:13:01 -0700164
165enum BleedTest {
166 kUseBitmap_BleedTest,
167 kUseImage_BleedTest,
168 kUseAlphaBitmap_BleedTest,
169 kUseAlphaImage_BleedTest,
170 kUseAlphaBitmapShader_BleedTest,
171 kUseAlphaImageShader_BleedTest,
172};
173
174const struct {
175 const char* fName;
bsalomona2e08372016-07-13 14:50:17 -0700176 bool (*fPixelMaker)(TestPixels* result, int width, int height);
reed2ad1aa62016-03-09 09:50:50 -0800177 sk_sp<SkShader> (*fShaderMaker)();
bsalomon9003d1e2015-10-23 11:13:01 -0700178} gBleedRec[] = {
bsalomon5c1262d2015-11-09 10:06:06 -0800179 { "bleed", make_ringed_color_bitmap, make_null_shader },
bsalomon5c1262d2015-11-09 10:06:06 -0800180 { "bleed_image", make_ringed_color_image, make_null_shader },
181 { "bleed_alpha_bmp", make_ringed_alpha_bitmap, make_null_shader },
bsalomon5c1262d2015-11-09 10:06:06 -0800182 { "bleed_alpha_image", make_ringed_alpha_image, make_null_shader },
183 { "bleed_alpha_bmp_shader", make_ringed_alpha_bitmap, make_shader },
bsalomon5c1262d2015-11-09 10:06:06 -0800184 { "bleed_alpha_image_shader", make_ringed_alpha_image, make_shader },
bsalomon9003d1e2015-10-23 11:13:01 -0700185};
186
bsalomon5c1262d2015-11-09 10:06:06 -0800187/** This GM exercises the behavior of the drawBitmapRect & drawImageRect calls. Specifically their
188 handling of :
189 - SrcRectConstraint(bleed vs.no - bleed)
190 - handling of the sub - region feature(area - of - interest) of drawBitmap*
191 - handling of 8888 vs. A8 (including presence of a shader in the A8 case).
bsalomon5c1262d2015-11-09 10:06:06 -0800192 In particular, we should never see the padding outside of an SkBitmap's sub - region (green for
193 8888, 1/4 for alpha). In some instances we can see the two outer rings outside of the area o
194 interest (i.e., the inner four checks) due to AA or filtering if allowed by the
195 SrcRectConstraint.
196*/
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000197class BleedGM : public skiagm::GM {
198public:
bsalomona2e08372016-07-13 14:50:17 -0700199 BleedGM(BleedTest bt) : fBT(bt){}
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000200
201protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000202
mtklein36352bf2015-03-25 18:17:31 -0700203 SkString onShortName() override {
reeda5517e22015-07-14 10:54:12 -0700204 return SkString(gBleedRec[fBT].fName);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000205 }
206
mtklein36352bf2015-03-25 18:17:31 -0700207 SkISize onISize() override {
bsalomonf57ef1c2015-11-04 04:36:12 -0800208 return SkISize::Make(1200, 1080);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000209 }
210
bsalomon5c1262d2015-11-09 10:06:06 -0800211 void drawPixels(SkCanvas* canvas, const TestPixels& pixels, const SkRect& src,
212 const SkRect& dst, const SkPaint* paint,
213 SkCanvas::SrcRectConstraint constraint) {
214 if (TestPixels::kBitmap == pixels.fType) {
215 canvas->drawBitmapRect(pixels.fBitmap, src, dst, paint, constraint);
216 } else {
reed9ce9d672016-03-17 10:51:11 -0700217 canvas->drawImageRect(pixels.fImage.get(), src, dst, paint, constraint);
bsalomon5c1262d2015-11-09 10:06:06 -0800218 }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000219 }
220
bsalomon5c1262d2015-11-09 10:06:06 -0800221 // Draw the area of interest of the small image
bsalomon9003d1e2015-10-23 11:13:01 -0700222 void drawCase1(SkCanvas* canvas, int transX, int transY, bool aa,
reeda5517e22015-07-14 10:54:12 -0700223 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800224
225 SkRect src = SkRect::Make(fSmallTestPixels.fRect);
reeda5517e22015-07-14 10:54:12 -0700226 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
227 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000228
229 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700230 paint.setFilterQuality(filter);
bsalomon9003d1e2015-10-23 11:13:01 -0700231 paint.setShader(fShader);
232 paint.setColor(SK_ColorBLUE);
233 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000234
bsalomon5c1262d2015-11-09 10:06:06 -0800235 this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000236 }
237
bsalomon5c1262d2015-11-09 10:06:06 -0800238 // Draw the area of interest of the large image
bsalomon9003d1e2015-10-23 11:13:01 -0700239 void drawCase2(SkCanvas* canvas, int transX, int transY, bool aa,
reeda5517e22015-07-14 10:54:12 -0700240 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800241 SkRect src = SkRect::Make(fBigTestPixels.fRect);
reeda5517e22015-07-14 10:54:12 -0700242 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
243 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000244
245 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700246 paint.setFilterQuality(filter);
bsalomon9003d1e2015-10-23 11:13:01 -0700247 paint.setShader(fShader);
248 paint.setColor(SK_ColorBLUE);
249 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000250
bsalomon5c1262d2015-11-09 10:06:06 -0800251 this->drawPixels(canvas, fBigTestPixels, src, dst, &paint, constraint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000252 }
253
bsalomon5c1262d2015-11-09 10:06:06 -0800254 // Draw upper-left 1/4 of the area of interest of the large image
bsalomon9003d1e2015-10-23 11:13:01 -0700255 void drawCase3(SkCanvas* canvas, int transX, int transY, bool aa,
reeda5517e22015-07-14 10:54:12 -0700256 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800257 SkRect src = SkRect::MakeXYWH(SkIntToScalar(fBigTestPixels.fRect.fLeft),
258 SkIntToScalar(fBigTestPixels.fRect.fTop),
259 fBigTestPixels.fRect.width()/2.f,
260 fBigTestPixels.fRect.height()/2.f);
reeda5517e22015-07-14 10:54:12 -0700261 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
262 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000263
264 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700265 paint.setFilterQuality(filter);
bsalomon9003d1e2015-10-23 11:13:01 -0700266 paint.setShader(fShader);
267 paint.setColor(SK_ColorBLUE);
268 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000269
bsalomon5c1262d2015-11-09 10:06:06 -0800270 this->drawPixels(canvas, fBigTestPixels, src, dst, &paint, constraint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000271 }
272
bsalomon5c1262d2015-11-09 10:06:06 -0800273 // Draw the area of interest of the small image with a normal blur
bsalomon9003d1e2015-10-23 11:13:01 -0700274 void drawCase4(SkCanvas* canvas, int transX, int transY, bool aa,
reeda5517e22015-07-14 10:54:12 -0700275 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800276 SkRect src = SkRect::Make(fSmallTestPixels.fRect);
reeda5517e22015-07-14 10:54:12 -0700277 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
278 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000279
280 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700281 paint.setFilterQuality(filter);
reedefdfd512016-04-04 10:02:58 -0700282 paint.setMaskFilter(SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
283 SkBlurMask::ConvertRadiusToSigma(3)));
bsalomon9003d1e2015-10-23 11:13:01 -0700284 paint.setShader(fShader);
285 paint.setColor(SK_ColorBLUE);
286 paint.setAntiAlias(aa);
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000287
bsalomon5c1262d2015-11-09 10:06:06 -0800288 this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000289 }
290
bsalomon5c1262d2015-11-09 10:06:06 -0800291 // Draw the area of interest of the small image with a outer blur
bsalomonf57ef1c2015-11-04 04:36:12 -0800292 void drawCase5(SkCanvas* canvas, int transX, int transY, bool aa,
293 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800294 SkRect src = SkRect::Make(fSmallTestPixels.fRect);
bsalomonf57ef1c2015-11-04 04:36:12 -0800295 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
296 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
297
298 SkPaint paint;
299 paint.setFilterQuality(filter);
reedefdfd512016-04-04 10:02:58 -0700300 paint.setMaskFilter(SkBlurMaskFilter::Make(kOuter_SkBlurStyle,
301 SkBlurMask::ConvertRadiusToSigma(7)));
bsalomonf57ef1c2015-11-04 04:36:12 -0800302 paint.setShader(fShader);
303 paint.setColor(SK_ColorBLUE);
304 paint.setAntiAlias(aa);
305
bsalomon5c1262d2015-11-09 10:06:06 -0800306 this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
bsalomonf57ef1c2015-11-04 04:36:12 -0800307 }
308
bsalomona2e08372016-07-13 14:50:17 -0700309 void onOnceBeforeDraw() override {
310 SkAssertResult(gBleedRec[fBT].fPixelMaker(&fSmallTestPixels, kSmallSize, kSmallSize));
311 SkAssertResult(gBleedRec[fBT].fPixelMaker(&fBigTestPixels, 2 * kMaxTileSize,
312 2 * kMaxTileSize));
313 }
314
mtklein36352bf2015-03-25 18:17:31 -0700315 void onDraw(SkCanvas* canvas) override {
reed2ad1aa62016-03-09 09:50:50 -0800316 fShader = gBleedRec[fBT].fShaderMaker();
bsalomon5c1262d2015-11-09 10:06:06 -0800317
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000318 canvas->clear(SK_ColorGRAY);
bsalomon9003d1e2015-10-23 11:13:01 -0700319 SkTDArray<SkMatrix> matrices;
320 // Draw with identity
321 *matrices.append() = SkMatrix::I();
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000322
bsalomon9003d1e2015-10-23 11:13:01 -0700323 // Draw with rotation and scale down in x, up in y.
324 SkMatrix m;
mtkleindbfd7ab2016-09-01 11:24:54 -0700325 constexpr SkScalar kBottom = SkIntToScalar(kRow4Y + kBlockSize + kBlockSpacing);
bsalomon9003d1e2015-10-23 11:13:01 -0700326 m.setTranslate(0, kBottom);
327 m.preRotate(15.f, 0, kBottom + kBlockSpacing);
328 m.preScale(0.71f, 1.22f);
329 *matrices.append() = m;
330
331 // Align the next set with the middle of the previous in y, translated to the right in x.
332 SkPoint corners[] = {{0, 0}, { 0, kBottom }, { kWidth, kBottom }, {kWidth, 0} };
333 matrices[matrices.count()-1].mapPoints(corners, 4);
334 SkScalar y = (corners[0].fY + corners[1].fY + corners[2].fY + corners[3].fY) / 4;
335 SkScalar x = SkTMax(SkTMax(corners[0].fX, corners[1].fX),
336 SkTMax(corners[2].fX, corners[3].fX));
337 m.setTranslate(x, y);
338 m.preScale(0.2f, 0.2f);
339 *matrices.append() = m;
340
341 SkScalar maxX = 0;
342 for (int antiAlias = 0; antiAlias < 2; ++antiAlias) {
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000343 canvas->save();
bsalomon9003d1e2015-10-23 11:13:01 -0700344 canvas->translate(maxX, 0);
345 for (int m = 0; m < matrices.count(); ++m) {
346 canvas->save();
347 canvas->concat(matrices[m]);
348 bool aa = SkToBool(antiAlias);
349
350 // First draw a column with no bleeding and no filtering
351 this->drawCase1(canvas, kCol0X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
352 this->drawCase2(canvas, kCol0X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
353 this->drawCase3(canvas, kCol0X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
354 this->drawCase4(canvas, kCol0X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800355 this->drawCase5(canvas, kCol0X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700356
357 // Then draw a column with no bleeding and low filtering
358 this->drawCase1(canvas, kCol1X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
359 this->drawCase2(canvas, kCol1X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
360 this->drawCase3(canvas, kCol1X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
361 this->drawCase4(canvas, kCol1X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800362 this->drawCase5(canvas, kCol1X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700363
364 // Then draw a column with no bleeding and high filtering
365 this->drawCase1(canvas, kCol2X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
366 this->drawCase2(canvas, kCol2X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
367 this->drawCase3(canvas, kCol2X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
368 this->drawCase4(canvas, kCol2X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800369 this->drawCase5(canvas, kCol2X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700370
371 // Then draw a column with bleeding and no filtering (bleed should have no effect w/out blur)
372 this->drawCase1(canvas, kCol3X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
373 this->drawCase2(canvas, kCol3X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
374 this->drawCase3(canvas, kCol3X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
375 this->drawCase4(canvas, kCol3X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800376 this->drawCase5(canvas, kCol3X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700377
378 // Then draw a column with bleeding and low filtering
379 this->drawCase1(canvas, kCol4X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
380 this->drawCase2(canvas, kCol4X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
381 this->drawCase3(canvas, kCol4X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
382 this->drawCase4(canvas, kCol4X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800383 this->drawCase5(canvas, kCol4X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700384
385 // Finally draw a column with bleeding and high filtering
386 this->drawCase1(canvas, kCol5X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
387 this->drawCase2(canvas, kCol5X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
388 this->drawCase3(canvas, kCol5X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
389 this->drawCase4(canvas, kCol5X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800390 this->drawCase5(canvas, kCol5X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700391
392 SkPoint corners[] = { { 0, 0 },{ 0, kBottom },{ kWidth, kBottom },{ kWidth, 0 } };
393 matrices[m].mapPoints(corners, 4);
394 SkScalar x = kBlockSize + SkTMax(SkTMax(corners[0].fX, corners[1].fX),
395 SkTMax(corners[2].fX, corners[3].fX));
396 maxX = SkTMax(maxX, x);
397 canvas->restore();
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000398 }
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000399 canvas->restore();
400 }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000401 }
402
bsalomon4ee6bd82015-05-27 13:23:23 -0700403#if SK_SUPPORT_GPU
404 void modifyGrContextOptions(GrContextOptions* options) override {
bsalomon8c07b7a2015-11-02 11:36:52 -0800405 options->fMaxTileSizeOverride = kMaxTileSize;
bsalomon4ee6bd82015-05-27 13:23:23 -0700406 }
407#endif
408
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000409private:
mtkleindbfd7ab2016-09-01 11:24:54 -0700410 static constexpr int kBlockSize = 70;
411 static constexpr int kBlockSpacing = 12;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000412
mtkleindbfd7ab2016-09-01 11:24:54 -0700413 static constexpr int kCol0X = kBlockSpacing;
414 static constexpr int kCol1X = 2*kBlockSpacing + kBlockSize;
415 static constexpr int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
416 static constexpr int kCol3X = 4*kBlockSpacing + 3*kBlockSize;
417 static constexpr int kCol4X = 5*kBlockSpacing + 4*kBlockSize;
418 static constexpr int kCol5X = 6*kBlockSpacing + 5*kBlockSize;
419 static constexpr int kWidth = 7*kBlockSpacing + 6*kBlockSize;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000420
mtkleindbfd7ab2016-09-01 11:24:54 -0700421 static constexpr int kRow0Y = kBlockSpacing;
422 static constexpr int kRow1Y = 2*kBlockSpacing + kBlockSize;
423 static constexpr int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
424 static constexpr int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
425 static constexpr int kRow4Y = 5*kBlockSpacing + 4*kBlockSize;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000426
mtkleindbfd7ab2016-09-01 11:24:54 -0700427 static constexpr int kSmallSize = 6;
428 static constexpr int kMaxTileSize = 32;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000429
reed2ad1aa62016-03-09 09:50:50 -0800430 TestPixels fBigTestPixels;
431 TestPixels fSmallTestPixels;
bsalomon9003d1e2015-10-23 11:13:01 -0700432
reed2ad1aa62016-03-09 09:50:50 -0800433 sk_sp<SkShader> fShader;
bsalomon9003d1e2015-10-23 11:13:01 -0700434
reed2ad1aa62016-03-09 09:50:50 -0800435 const BleedTest fBT;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000436
437 typedef GM INHERITED;
438};
439
bsalomon9c586542015-11-02 12:33:21 -0800440
reeda5517e22015-07-14 10:54:12 -0700441DEF_GM( return new BleedGM(kUseBitmap_BleedTest); )
442DEF_GM( return new BleedGM(kUseImage_BleedTest); )
bsalomon9003d1e2015-10-23 11:13:01 -0700443DEF_GM( return new BleedGM(kUseAlphaBitmap_BleedTest); )
444DEF_GM( return new BleedGM(kUseAlphaImage_BleedTest); )
bsalomon9c586542015-11-02 12:33:21 -0800445DEF_GM( return new BleedGM(kUseAlphaBitmapShader_BleedTest); )
bsalomon9c586542015-11-02 12:33:21 -0800446DEF_GM( return new BleedGM(kUseAlphaImageShader_BleedTest); )
reed2adecda2016-07-25 08:11:58 -0700447
448///////////////////////////////////////////////////////////////////////////////////////////////////
449#include "SkSurface.h"
450
451sk_sp<SkSurface> make_surface(SkCanvas* canvas, const SkImageInfo& info) {
452 auto surface = canvas->makeSurface(info);
453 if (!surface) {
454 surface = SkSurface::MakeRaster(info);
455 }
456 return surface;
457}
458
459// Construct an image and return the inner "src" rect. Build the image such that the interior is
460// blue, with a margin of blue (2px) but then an outer margin of red.
461//
462// Show that kFast_SrcRectConstraint sees even the red margin (due to mipmapping) when the image
463// is scaled down far enough.
464//
465static sk_sp<SkImage> make_image(SkCanvas* canvas, SkRect* srcR) {
egdaniel26318c92016-07-26 08:26:46 -0700466 // Intentially making the size a power of 2 to avoid the noise from how different GPUs will
467 // produce different mipmap filtering when we have an odd sized texture.
468 const int N = 10 + 2 + 8 + 2 + 10;
reed2adecda2016-07-25 08:11:58 -0700469 SkImageInfo info = SkImageInfo::MakeN32Premul(N, N);
470 auto surface = make_surface(canvas, info);
471 SkCanvas* c = surface->getCanvas();
472 SkRect r = SkRect::MakeIWH(info.width(), info.height());
473 SkPaint paint;
474
475 paint.setColor(SK_ColorRED);
476 c->drawRect(r, paint);
egdaniel26318c92016-07-26 08:26:46 -0700477 r.inset(10, 10);
reed2adecda2016-07-25 08:11:58 -0700478 paint.setColor(SK_ColorBLUE);
479 c->drawRect(r, paint);
480
481 *srcR = r.makeInset(2, 2);
482 return surface->makeImageSnapshot();
483}
484
485DEF_SIMPLE_GM(bleed_downscale, canvas, 360, 240) {
486 SkRect src;
487 sk_sp<SkImage> img = make_image(canvas, &src);
488 SkPaint paint;
489
490 canvas->translate(10, 10);
491
492 const SkCanvas::SrcRectConstraint constraints[] = {
493 SkCanvas::kStrict_SrcRectConstraint, SkCanvas::kFast_SrcRectConstraint
494 };
495 const SkFilterQuality qualities[] = {
496 kNone_SkFilterQuality, kLow_SkFilterQuality, kMedium_SkFilterQuality
497 };
498 for (auto constraint : constraints) {
499 canvas->save();
500 for (auto quality : qualities) {
501 paint.setFilterQuality(quality);
502 auto surf = make_surface(canvas, SkImageInfo::MakeN32Premul(1, 1));
503 surf->getCanvas()->drawImageRect(img, src, SkRect::MakeWH(1, 1), &paint, constraint);
504 // now blow up the 1 pixel result
505 canvas->drawImageRect(surf->makeImageSnapshot(), SkRect::MakeWH(100, 100), nullptr);
506 canvas->translate(120, 0);
507 }
508 canvas->restore();
509 canvas->translate(0, 120);
510 }
511}
512
513