blob: 1bb8b2b029c73bb3607869d8e7b0b3b6dd480540 [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"
Mike Klein33d20552017-03-22 13:47:51 -040014#include "SkTDArray.h"
bsalomon9c586542015-11-02 12:33:21 -080015#include "SkUtils.h"
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000016
17#if SK_SUPPORT_GPU
18#include "GrContext.h"
bsalomon4ee6bd82015-05-27 13:23:23 -070019#include "GrContextOptions.h"
bsalomon9c586542015-11-02 12:33:21 -080020#include "SkGr.h"
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000021#endif
22
bsalomon5c1262d2015-11-09 10:06:06 -080023/** Holds either a bitmap or image to be rendered and a rect that indicates what part of the bitmap
24 or image should be tested by the GM. The area outside of the rect is present to check
25 for bleed due to filtering/blurring. */
26struct TestPixels {
27 enum Type {
28 kBitmap,
29 kImage
30 };
reed9ce9d672016-03-17 10:51:11 -070031 Type fType;
32 SkBitmap fBitmap;
33 sk_sp<SkImage> fImage;
34 SkIRect fRect; // The region of the bitmap/image that should be rendered.
bsalomon5c1262d2015-11-09 10:06:06 -080035};
reeda5517e22015-07-14 10:54:12 -070036
bsalomon5c1262d2015-11-09 10:06:06 -080037/** Creates a bitmap with two one-pixel rings around a checkerboard. The checkerboard is 2x2
38 logically where each check has as many pixels as is necessary to fill the interior. The rect
39 to draw is set to the checkerboard portion. */
40template<typename PIXEL_TYPE>
bsalomona2e08372016-07-13 14:50:17 -070041bool make_ringed_bitmap(TestPixels* result, int width, int height,
bsalomon5c1262d2015-11-09 10:06:06 -080042 SkColorType ct, SkAlphaType at,
43 PIXEL_TYPE outerRingColor, PIXEL_TYPE innerRingColor,
44 PIXEL_TYPE checkColor1, PIXEL_TYPE checkColor2) {
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +000045 SkASSERT(0 == width % 2 && 0 == height % 2);
bsalomon5c1262d2015-11-09 10:06:06 -080046 SkASSERT(width >= 6 && height >= 6);
skia.committer@gmail.comed000842013-11-09 07:02:23 +000047
bsalomon5c1262d2015-11-09 10:06:06 -080048 result->fType = TestPixels::kBitmap;
49 SkImageInfo info = SkImageInfo::Make(width, height, ct, at);
50 size_t rowBytes = SkAlign4(info.minRowBytes());
51 result->fBitmap.allocPixels(info, rowBytes);
52
53 PIXEL_TYPE* scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, 0);
54 for (int x = 0; x < width; ++x) {
55 scanline[x] = outerRingColor;
56 }
57 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, 1);
58 scanline[0] = outerRingColor;
59 for (int x = 1; x < width - 1; ++x) {
60 scanline[x] = innerRingColor;
61 }
62 scanline[width - 1] = outerRingColor;
63
64 for (int y = 2; y < height / 2; ++y) {
65 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, y);
66 scanline[0] = outerRingColor;
67 scanline[1] = innerRingColor;
68 for (int x = 2; x < width / 2; ++x) {
69 scanline[x] = checkColor1;
70 }
71 for (int x = width / 2; x < width - 2; ++x) {
72 scanline[x] = checkColor2;
73 }
74 scanline[width - 2] = innerRingColor;
75 scanline[width - 1] = outerRingColor;
76 }
77
78 for (int y = height / 2; y < height - 2; ++y) {
79 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, y);
80 scanline[0] = outerRingColor;
81 scanline[1] = innerRingColor;
82 for (int x = 2; x < width / 2; ++x) {
83 scanline[x] = checkColor2;
84 }
85 for (int x = width / 2; x < width - 2; ++x) {
86 scanline[x] = checkColor1;
87 }
88 scanline[width - 2] = innerRingColor;
89 scanline[width - 1] = outerRingColor;
90 }
91
92 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, height - 2);
93 scanline[0] = outerRingColor;
94 for (int x = 1; x < width - 1; ++x) {
95 scanline[x] = innerRingColor;
96 }
97 scanline[width - 1] = outerRingColor;
98
99 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, height - 1);
100 for (int x = 0; x < width; ++x) {
101 scanline[x] = outerRingColor;
102 }
103 result->fBitmap.setImmutable();
104 result->fRect.set(2, 2, width - 2, height - 2);
105 return true;
106}
107
bsalomona2e08372016-07-13 14:50:17 -0700108/** Create a black and white checked bitmap with 2 1-pixel rings around the outside edge.
bsalomon5c1262d2015-11-09 10:06:06 -0800109 The inner ring is red and the outer ring is blue. */
bsalomona2e08372016-07-13 14:50:17 -0700110static bool make_ringed_color_bitmap(TestPixels* result, int width, int height) {
mtkleindbfd7ab2016-09-01 11:24:54 -0700111 const SkPMColor kBlue = SkPreMultiplyColor(SK_ColorBLUE);
112 const SkPMColor kRed = SkPreMultiplyColor(SK_ColorRED);
113 const SkPMColor kBlack = SkPreMultiplyColor(SK_ColorBLACK);
114 const SkPMColor kWhite = SkPreMultiplyColor(SK_ColorWHITE);
bsalomon48b24612016-08-25 06:45:29 -0700115 return make_ringed_bitmap<SkPMColor>(result, width, height, kN32_SkColorType,
bsalomon5c1262d2015-11-09 10:06:06 -0800116 kPremul_SkAlphaType, kBlue, kRed, kBlack, kWhite);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000117}
118
bsalomondf85a722015-11-04 04:23:45 -0800119/** 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 -0700120 checker board of 3/4 and 1/2. The inner checkers are large enough to fill the interior with
121 the 2x2 checker grid. */
bsalomona2e08372016-07-13 14:50:17 -0700122static bool make_ringed_alpha_bitmap(TestPixels* result, int width, int height) {
mtkleindbfd7ab2016-09-01 11:24:54 -0700123 constexpr uint8_t kZero = 0x00;
124 constexpr uint8_t kHalf = 0x80;
125 constexpr uint8_t k3Q = 0xC0;
126 constexpr uint8_t kOne = 0xFF;
bsalomona2e08372016-07-13 14:50:17 -0700127 return make_ringed_bitmap<uint8_t>(result, width, height, kAlpha_8_SkColorType,
bsalomon5c1262d2015-11-09 10:06:06 -0800128 kPremul_SkAlphaType, kZero, kOne, k3Q, kHalf);
129}
130
131/** Helper to reuse above functions to produce images rather than bmps */
132static void bmp_to_image(TestPixels* result) {
133 SkASSERT(TestPixels::kBitmap == result->fType);
reed9ce9d672016-03-17 10:51:11 -0700134 result->fImage = SkImage::MakeFromBitmap(result->fBitmap);
bsalomon5c1262d2015-11-09 10:06:06 -0800135 SkASSERT(result->fImage);
136 result->fType = TestPixels::kImage;
137 result->fBitmap.reset();
138}
139
140/** Color image case. */
bsalomona2e08372016-07-13 14:50:17 -0700141bool make_ringed_color_image(TestPixels* result, int width, int height) {
142 if (make_ringed_color_bitmap(result, width, height)) {
bsalomon5c1262d2015-11-09 10:06:06 -0800143 bmp_to_image(result);
144 return true;
145 }
146 return false;
147}
148
149/** Alpha image case. */
bsalomona2e08372016-07-13 14:50:17 -0700150bool make_ringed_alpha_image(TestPixels* result, int width, int height) {
151 if (make_ringed_alpha_bitmap(result, width, height)) {
bsalomon5c1262d2015-11-09 10:06:06 -0800152 bmp_to_image(result);
153 return true;
154 }
155 return false;
156}
157
reed2ad1aa62016-03-09 09:50:50 -0800158static sk_sp<SkShader> make_shader() {
mtkleindbfd7ab2016-09-01 11:24:54 -0700159 constexpr SkPoint pts[] = { {0, 0}, {20, 20} };
160 constexpr SkColor colors[] = { SK_ColorGREEN, SK_ColorYELLOW };
reed2ad1aa62016-03-09 09:50:50 -0800161 return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kMirror_TileMode);
bsalomon9003d1e2015-10-23 11:13:01 -0700162}
163
reed2ad1aa62016-03-09 09:50:50 -0800164static sk_sp<SkShader> make_null_shader() { return nullptr; }
bsalomon9003d1e2015-10-23 11:13:01 -0700165
166enum BleedTest {
167 kUseBitmap_BleedTest,
168 kUseImage_BleedTest,
169 kUseAlphaBitmap_BleedTest,
170 kUseAlphaImage_BleedTest,
171 kUseAlphaBitmapShader_BleedTest,
172 kUseAlphaImageShader_BleedTest,
173};
174
175const struct {
176 const char* fName;
bsalomona2e08372016-07-13 14:50:17 -0700177 bool (*fPixelMaker)(TestPixels* result, int width, int height);
reed2ad1aa62016-03-09 09:50:50 -0800178 sk_sp<SkShader> (*fShaderMaker)();
bsalomon9003d1e2015-10-23 11:13:01 -0700179} gBleedRec[] = {
bsalomon5c1262d2015-11-09 10:06:06 -0800180 { "bleed", make_ringed_color_bitmap, make_null_shader },
bsalomon5c1262d2015-11-09 10:06:06 -0800181 { "bleed_image", make_ringed_color_image, make_null_shader },
182 { "bleed_alpha_bmp", make_ringed_alpha_bitmap, make_null_shader },
bsalomon5c1262d2015-11-09 10:06:06 -0800183 { "bleed_alpha_image", make_ringed_alpha_image, make_null_shader },
184 { "bleed_alpha_bmp_shader", make_ringed_alpha_bitmap, make_shader },
bsalomon5c1262d2015-11-09 10:06:06 -0800185 { "bleed_alpha_image_shader", make_ringed_alpha_image, make_shader },
bsalomon9003d1e2015-10-23 11:13:01 -0700186};
187
bsalomon5c1262d2015-11-09 10:06:06 -0800188/** This GM exercises the behavior of the drawBitmapRect & drawImageRect calls. Specifically their
189 handling of :
190 - SrcRectConstraint(bleed vs.no - bleed)
191 - handling of the sub - region feature(area - of - interest) of drawBitmap*
192 - handling of 8888 vs. A8 (including presence of a shader in the A8 case).
bsalomon5c1262d2015-11-09 10:06:06 -0800193 In particular, we should never see the padding outside of an SkBitmap's sub - region (green for
194 8888, 1/4 for alpha). In some instances we can see the two outer rings outside of the area o
195 interest (i.e., the inner four checks) due to AA or filtering if allowed by the
196 SrcRectConstraint.
197*/
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000198class BleedGM : public skiagm::GM {
199public:
bsalomona2e08372016-07-13 14:50:17 -0700200 BleedGM(BleedTest bt) : fBT(bt){}
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000201
202protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000203
mtklein36352bf2015-03-25 18:17:31 -0700204 SkString onShortName() override {
reeda5517e22015-07-14 10:54:12 -0700205 return SkString(gBleedRec[fBT].fName);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000206 }
207
mtklein36352bf2015-03-25 18:17:31 -0700208 SkISize onISize() override {
bsalomonf57ef1c2015-11-04 04:36:12 -0800209 return SkISize::Make(1200, 1080);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000210 }
211
bsalomon5c1262d2015-11-09 10:06:06 -0800212 void drawPixels(SkCanvas* canvas, const TestPixels& pixels, const SkRect& src,
213 const SkRect& dst, const SkPaint* paint,
214 SkCanvas::SrcRectConstraint constraint) {
215 if (TestPixels::kBitmap == pixels.fType) {
216 canvas->drawBitmapRect(pixels.fBitmap, src, dst, paint, constraint);
217 } else {
reed9ce9d672016-03-17 10:51:11 -0700218 canvas->drawImageRect(pixels.fImage.get(), src, dst, paint, constraint);
bsalomon5c1262d2015-11-09 10:06:06 -0800219 }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000220 }
221
bsalomon5c1262d2015-11-09 10:06:06 -0800222 // Draw the area of interest of the small image
bsalomon9003d1e2015-10-23 11:13:01 -0700223 void drawCase1(SkCanvas* canvas, int transX, int transY, bool aa,
reeda5517e22015-07-14 10:54:12 -0700224 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800225
226 SkRect src = SkRect::Make(fSmallTestPixels.fRect);
reeda5517e22015-07-14 10:54:12 -0700227 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
228 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000229
230 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700231 paint.setFilterQuality(filter);
bsalomon9003d1e2015-10-23 11:13:01 -0700232 paint.setShader(fShader);
233 paint.setColor(SK_ColorBLUE);
234 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000235
bsalomon5c1262d2015-11-09 10:06:06 -0800236 this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000237 }
238
bsalomon5c1262d2015-11-09 10:06:06 -0800239 // Draw the area of interest of the large image
bsalomon9003d1e2015-10-23 11:13:01 -0700240 void drawCase2(SkCanvas* canvas, int transX, int transY, bool aa,
reeda5517e22015-07-14 10:54:12 -0700241 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800242 SkRect src = SkRect::Make(fBigTestPixels.fRect);
reeda5517e22015-07-14 10:54:12 -0700243 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
244 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000245
246 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700247 paint.setFilterQuality(filter);
bsalomon9003d1e2015-10-23 11:13:01 -0700248 paint.setShader(fShader);
249 paint.setColor(SK_ColorBLUE);
250 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000251
bsalomon5c1262d2015-11-09 10:06:06 -0800252 this->drawPixels(canvas, fBigTestPixels, src, dst, &paint, constraint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000253 }
254
bsalomon5c1262d2015-11-09 10:06:06 -0800255 // Draw upper-left 1/4 of the area of interest of the large image
bsalomon9003d1e2015-10-23 11:13:01 -0700256 void drawCase3(SkCanvas* canvas, int transX, int transY, bool aa,
reeda5517e22015-07-14 10:54:12 -0700257 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800258 SkRect src = SkRect::MakeXYWH(SkIntToScalar(fBigTestPixels.fRect.fLeft),
259 SkIntToScalar(fBigTestPixels.fRect.fTop),
260 fBigTestPixels.fRect.width()/2.f,
261 fBigTestPixels.fRect.height()/2.f);
reeda5517e22015-07-14 10:54:12 -0700262 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
263 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000264
265 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700266 paint.setFilterQuality(filter);
bsalomon9003d1e2015-10-23 11:13:01 -0700267 paint.setShader(fShader);
268 paint.setColor(SK_ColorBLUE);
269 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000270
bsalomon5c1262d2015-11-09 10:06:06 -0800271 this->drawPixels(canvas, fBigTestPixels, src, dst, &paint, constraint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000272 }
273
bsalomon5c1262d2015-11-09 10:06:06 -0800274 // Draw the area of interest of the small image with a normal blur
bsalomon9003d1e2015-10-23 11:13:01 -0700275 void drawCase4(SkCanvas* canvas, int transX, int transY, bool aa,
reeda5517e22015-07-14 10:54:12 -0700276 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800277 SkRect src = SkRect::Make(fSmallTestPixels.fRect);
reeda5517e22015-07-14 10:54:12 -0700278 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
279 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000280
281 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700282 paint.setFilterQuality(filter);
reedefdfd512016-04-04 10:02:58 -0700283 paint.setMaskFilter(SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
284 SkBlurMask::ConvertRadiusToSigma(3)));
bsalomon9003d1e2015-10-23 11:13:01 -0700285 paint.setShader(fShader);
286 paint.setColor(SK_ColorBLUE);
287 paint.setAntiAlias(aa);
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000288
bsalomon5c1262d2015-11-09 10:06:06 -0800289 this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000290 }
291
bsalomon5c1262d2015-11-09 10:06:06 -0800292 // Draw the area of interest of the small image with a outer blur
bsalomonf57ef1c2015-11-04 04:36:12 -0800293 void drawCase5(SkCanvas* canvas, int transX, int transY, bool aa,
294 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800295 SkRect src = SkRect::Make(fSmallTestPixels.fRect);
bsalomonf57ef1c2015-11-04 04:36:12 -0800296 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
297 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
298
299 SkPaint paint;
300 paint.setFilterQuality(filter);
reedefdfd512016-04-04 10:02:58 -0700301 paint.setMaskFilter(SkBlurMaskFilter::Make(kOuter_SkBlurStyle,
302 SkBlurMask::ConvertRadiusToSigma(7)));
bsalomonf57ef1c2015-11-04 04:36:12 -0800303 paint.setShader(fShader);
304 paint.setColor(SK_ColorBLUE);
305 paint.setAntiAlias(aa);
306
bsalomon5c1262d2015-11-09 10:06:06 -0800307 this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
bsalomonf57ef1c2015-11-04 04:36:12 -0800308 }
309
bsalomona2e08372016-07-13 14:50:17 -0700310 void onOnceBeforeDraw() override {
311 SkAssertResult(gBleedRec[fBT].fPixelMaker(&fSmallTestPixels, kSmallSize, kSmallSize));
312 SkAssertResult(gBleedRec[fBT].fPixelMaker(&fBigTestPixels, 2 * kMaxTileSize,
313 2 * kMaxTileSize));
314 }
315
mtklein36352bf2015-03-25 18:17:31 -0700316 void onDraw(SkCanvas* canvas) override {
reed2ad1aa62016-03-09 09:50:50 -0800317 fShader = gBleedRec[fBT].fShaderMaker();
bsalomon5c1262d2015-11-09 10:06:06 -0800318
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000319 canvas->clear(SK_ColorGRAY);
bsalomon9003d1e2015-10-23 11:13:01 -0700320 SkTDArray<SkMatrix> matrices;
321 // Draw with identity
322 *matrices.append() = SkMatrix::I();
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000323
bsalomon9003d1e2015-10-23 11:13:01 -0700324 // Draw with rotation and scale down in x, up in y.
325 SkMatrix m;
mtkleindbfd7ab2016-09-01 11:24:54 -0700326 constexpr SkScalar kBottom = SkIntToScalar(kRow4Y + kBlockSize + kBlockSpacing);
bsalomon9003d1e2015-10-23 11:13:01 -0700327 m.setTranslate(0, kBottom);
328 m.preRotate(15.f, 0, kBottom + kBlockSpacing);
329 m.preScale(0.71f, 1.22f);
330 *matrices.append() = m;
331
332 // Align the next set with the middle of the previous in y, translated to the right in x.
333 SkPoint corners[] = {{0, 0}, { 0, kBottom }, { kWidth, kBottom }, {kWidth, 0} };
334 matrices[matrices.count()-1].mapPoints(corners, 4);
335 SkScalar y = (corners[0].fY + corners[1].fY + corners[2].fY + corners[3].fY) / 4;
336 SkScalar x = SkTMax(SkTMax(corners[0].fX, corners[1].fX),
337 SkTMax(corners[2].fX, corners[3].fX));
338 m.setTranslate(x, y);
339 m.preScale(0.2f, 0.2f);
340 *matrices.append() = m;
341
342 SkScalar maxX = 0;
343 for (int antiAlias = 0; antiAlias < 2; ++antiAlias) {
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000344 canvas->save();
bsalomon9003d1e2015-10-23 11:13:01 -0700345 canvas->translate(maxX, 0);
346 for (int m = 0; m < matrices.count(); ++m) {
347 canvas->save();
348 canvas->concat(matrices[m]);
349 bool aa = SkToBool(antiAlias);
350
351 // First draw a column with no bleeding and no filtering
352 this->drawCase1(canvas, kCol0X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
353 this->drawCase2(canvas, kCol0X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
354 this->drawCase3(canvas, kCol0X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
355 this->drawCase4(canvas, kCol0X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800356 this->drawCase5(canvas, kCol0X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700357
358 // Then draw a column with no bleeding and low filtering
359 this->drawCase1(canvas, kCol1X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
360 this->drawCase2(canvas, kCol1X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
361 this->drawCase3(canvas, kCol1X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
362 this->drawCase4(canvas, kCol1X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800363 this->drawCase5(canvas, kCol1X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700364
365 // Then draw a column with no bleeding and high filtering
366 this->drawCase1(canvas, kCol2X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
367 this->drawCase2(canvas, kCol2X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
368 this->drawCase3(canvas, kCol2X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
369 this->drawCase4(canvas, kCol2X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800370 this->drawCase5(canvas, kCol2X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700371
372 // Then draw a column with bleeding and no filtering (bleed should have no effect w/out blur)
373 this->drawCase1(canvas, kCol3X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
374 this->drawCase2(canvas, kCol3X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
375 this->drawCase3(canvas, kCol3X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
376 this->drawCase4(canvas, kCol3X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800377 this->drawCase5(canvas, kCol3X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700378
379 // Then draw a column with bleeding and low filtering
380 this->drawCase1(canvas, kCol4X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
381 this->drawCase2(canvas, kCol4X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
382 this->drawCase3(canvas, kCol4X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
383 this->drawCase4(canvas, kCol4X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800384 this->drawCase5(canvas, kCol4X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700385
386 // Finally draw a column with bleeding and high filtering
387 this->drawCase1(canvas, kCol5X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
388 this->drawCase2(canvas, kCol5X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
389 this->drawCase3(canvas, kCol5X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
390 this->drawCase4(canvas, kCol5X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800391 this->drawCase5(canvas, kCol5X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700392
393 SkPoint corners[] = { { 0, 0 },{ 0, kBottom },{ kWidth, kBottom },{ kWidth, 0 } };
394 matrices[m].mapPoints(corners, 4);
395 SkScalar x = kBlockSize + SkTMax(SkTMax(corners[0].fX, corners[1].fX),
396 SkTMax(corners[2].fX, corners[3].fX));
397 maxX = SkTMax(maxX, x);
398 canvas->restore();
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000399 }
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000400 canvas->restore();
401 }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000402 }
403
bsalomon4ee6bd82015-05-27 13:23:23 -0700404#if SK_SUPPORT_GPU
405 void modifyGrContextOptions(GrContextOptions* options) override {
bsalomon8c07b7a2015-11-02 11:36:52 -0800406 options->fMaxTileSizeOverride = kMaxTileSize;
bsalomon4ee6bd82015-05-27 13:23:23 -0700407 }
408#endif
409
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000410private:
mtkleindbfd7ab2016-09-01 11:24:54 -0700411 static constexpr int kBlockSize = 70;
412 static constexpr int kBlockSpacing = 12;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000413
mtkleindbfd7ab2016-09-01 11:24:54 -0700414 static constexpr int kCol0X = kBlockSpacing;
415 static constexpr int kCol1X = 2*kBlockSpacing + kBlockSize;
416 static constexpr int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
417 static constexpr int kCol3X = 4*kBlockSpacing + 3*kBlockSize;
418 static constexpr int kCol4X = 5*kBlockSpacing + 4*kBlockSize;
419 static constexpr int kCol5X = 6*kBlockSpacing + 5*kBlockSize;
420 static constexpr int kWidth = 7*kBlockSpacing + 6*kBlockSize;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000421
mtkleindbfd7ab2016-09-01 11:24:54 -0700422 static constexpr int kRow0Y = kBlockSpacing;
423 static constexpr int kRow1Y = 2*kBlockSpacing + kBlockSize;
424 static constexpr int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
425 static constexpr int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
426 static constexpr int kRow4Y = 5*kBlockSpacing + 4*kBlockSize;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000427
mtkleindbfd7ab2016-09-01 11:24:54 -0700428 static constexpr int kSmallSize = 6;
429 static constexpr int kMaxTileSize = 32;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000430
reed2ad1aa62016-03-09 09:50:50 -0800431 TestPixels fBigTestPixels;
432 TestPixels fSmallTestPixels;
bsalomon9003d1e2015-10-23 11:13:01 -0700433
reed2ad1aa62016-03-09 09:50:50 -0800434 sk_sp<SkShader> fShader;
bsalomon9003d1e2015-10-23 11:13:01 -0700435
reed2ad1aa62016-03-09 09:50:50 -0800436 const BleedTest fBT;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000437
438 typedef GM INHERITED;
439};
440
bsalomon9c586542015-11-02 12:33:21 -0800441
reeda5517e22015-07-14 10:54:12 -0700442DEF_GM( return new BleedGM(kUseBitmap_BleedTest); )
443DEF_GM( return new BleedGM(kUseImage_BleedTest); )
bsalomon9003d1e2015-10-23 11:13:01 -0700444DEF_GM( return new BleedGM(kUseAlphaBitmap_BleedTest); )
445DEF_GM( return new BleedGM(kUseAlphaImage_BleedTest); )
bsalomon9c586542015-11-02 12:33:21 -0800446DEF_GM( return new BleedGM(kUseAlphaBitmapShader_BleedTest); )
bsalomon9c586542015-11-02 12:33:21 -0800447DEF_GM( return new BleedGM(kUseAlphaImageShader_BleedTest); )
reed2adecda2016-07-25 08:11:58 -0700448
449///////////////////////////////////////////////////////////////////////////////////////////////////
450#include "SkSurface.h"
451
452sk_sp<SkSurface> make_surface(SkCanvas* canvas, const SkImageInfo& info) {
453 auto surface = canvas->makeSurface(info);
454 if (!surface) {
455 surface = SkSurface::MakeRaster(info);
456 }
457 return surface;
458}
459
460// Construct an image and return the inner "src" rect. Build the image such that the interior is
461// blue, with a margin of blue (2px) but then an outer margin of red.
462//
463// Show that kFast_SrcRectConstraint sees even the red margin (due to mipmapping) when the image
464// is scaled down far enough.
465//
466static sk_sp<SkImage> make_image(SkCanvas* canvas, SkRect* srcR) {
egdaniel26318c92016-07-26 08:26:46 -0700467 // Intentially making the size a power of 2 to avoid the noise from how different GPUs will
468 // produce different mipmap filtering when we have an odd sized texture.
469 const int N = 10 + 2 + 8 + 2 + 10;
reed2adecda2016-07-25 08:11:58 -0700470 SkImageInfo info = SkImageInfo::MakeN32Premul(N, N);
471 auto surface = make_surface(canvas, info);
472 SkCanvas* c = surface->getCanvas();
473 SkRect r = SkRect::MakeIWH(info.width(), info.height());
474 SkPaint paint;
475
476 paint.setColor(SK_ColorRED);
477 c->drawRect(r, paint);
egdaniel26318c92016-07-26 08:26:46 -0700478 r.inset(10, 10);
reed2adecda2016-07-25 08:11:58 -0700479 paint.setColor(SK_ColorBLUE);
480 c->drawRect(r, paint);
481
482 *srcR = r.makeInset(2, 2);
483 return surface->makeImageSnapshot();
484}
485
486DEF_SIMPLE_GM(bleed_downscale, canvas, 360, 240) {
487 SkRect src;
488 sk_sp<SkImage> img = make_image(canvas, &src);
489 SkPaint paint;
490
491 canvas->translate(10, 10);
492
493 const SkCanvas::SrcRectConstraint constraints[] = {
494 SkCanvas::kStrict_SrcRectConstraint, SkCanvas::kFast_SrcRectConstraint
495 };
496 const SkFilterQuality qualities[] = {
497 kNone_SkFilterQuality, kLow_SkFilterQuality, kMedium_SkFilterQuality
498 };
499 for (auto constraint : constraints) {
500 canvas->save();
501 for (auto quality : qualities) {
502 paint.setFilterQuality(quality);
503 auto surf = make_surface(canvas, SkImageInfo::MakeN32Premul(1, 1));
504 surf->getCanvas()->drawImageRect(img, src, SkRect::MakeWH(1, 1), &paint, constraint);
505 // now blow up the 1 pixel result
506 canvas->drawImageRect(surf->makeImageSnapshot(), SkRect::MakeWH(100, 100), nullptr);
507 canvas->translate(120, 0);
508 }
509 canvas->restore();
510 canvas->translate(0, 120);
511 }
512}
513
514