blob: baef8850d6d396109433f5bc018f1b6e43c11749 [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) {
bsalomon5c1262d2015-11-09 10:06:06 -0800110 static const SkPMColor kBlue = SkPreMultiplyColor(SK_ColorBLUE);
111 static const SkPMColor kRed = SkPreMultiplyColor(SK_ColorRED);
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000112 static const SkPMColor kBlack = SkPreMultiplyColor(SK_ColorBLACK);
113 static const SkPMColor kWhite = SkPreMultiplyColor(SK_ColorWHITE);
bsalomona2e08372016-07-13 14:50:17 -0700114 return make_ringed_bitmap<SkPMColor>(result, width, height, kBGRA_8888_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) {
bsalomon5c1262d2015-11-09 10:06:06 -0800122 static const uint8_t kZero = 0x00;
123 static const uint8_t kHalf = 0x80;
124 static const uint8_t k3Q = 0xC0;
125 static const 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() {
bsalomon9003d1e2015-10-23 11:13:01 -0700158 static const SkPoint pts[] = { {0, 0}, {20, 20} };
159 static const 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;
bsalomonf57ef1c2015-11-04 04:36:12 -0800325 static const 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:
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000410 static const int kBlockSize = 70;
bsalomonf57ef1c2015-11-04 04:36:12 -0800411 static const int kBlockSpacing = 12;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000412
413 static const int kCol0X = kBlockSpacing;
414 static const int kCol1X = 2*kBlockSpacing + kBlockSize;
415 static const int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
416 static const int kCol3X = 4*kBlockSpacing + 3*kBlockSize;
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000417 static const int kCol4X = 5*kBlockSpacing + 4*kBlockSize;
418 static const int kCol5X = 6*kBlockSpacing + 5*kBlockSize;
bsalomon4ee6bd82015-05-27 13:23:23 -0700419 static const int kWidth = 7*kBlockSpacing + 6*kBlockSize;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000420
421 static const int kRow0Y = kBlockSpacing;
422 static const int kRow1Y = 2*kBlockSpacing + kBlockSize;
423 static const int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000424 static const int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
bsalomonf57ef1c2015-11-04 04:36:12 -0800425 static const int kRow4Y = 5*kBlockSpacing + 4*kBlockSize;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000426
bsalomona2e08372016-07-13 14:50:17 -0700427 static const int kSmallSize = 6;
bsalomon8c07b7a2015-11-02 11:36:52 -0800428 static const 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) {
466 const int N = 9 + 2 + 7 + 2 + 9;
467 SkImageInfo info = SkImageInfo::MakeN32Premul(N, N);
468 auto surface = make_surface(canvas, info);
469 SkCanvas* c = surface->getCanvas();
470 SkRect r = SkRect::MakeIWH(info.width(), info.height());
471 SkPaint paint;
472
473 paint.setColor(SK_ColorRED);
474 c->drawRect(r, paint);
475 r.inset(4, 4);
476 paint.setColor(SK_ColorBLUE);
477 c->drawRect(r, paint);
478
479 *srcR = r.makeInset(2, 2);
480 return surface->makeImageSnapshot();
481}
482
483DEF_SIMPLE_GM(bleed_downscale, canvas, 360, 240) {
484 SkRect src;
485 sk_sp<SkImage> img = make_image(canvas, &src);
486 SkPaint paint;
487
488 canvas->translate(10, 10);
489
490 const SkCanvas::SrcRectConstraint constraints[] = {
491 SkCanvas::kStrict_SrcRectConstraint, SkCanvas::kFast_SrcRectConstraint
492 };
493 const SkFilterQuality qualities[] = {
494 kNone_SkFilterQuality, kLow_SkFilterQuality, kMedium_SkFilterQuality
495 };
496 for (auto constraint : constraints) {
497 canvas->save();
498 for (auto quality : qualities) {
499 paint.setFilterQuality(quality);
500 auto surf = make_surface(canvas, SkImageInfo::MakeN32Premul(1, 1));
501 surf->getCanvas()->drawImageRect(img, src, SkRect::MakeWH(1, 1), &paint, constraint);
502 // now blow up the 1 pixel result
503 canvas->drawImageRect(surf->makeImageSnapshot(), SkRect::MakeWH(100, 100), nullptr);
504 canvas->translate(120, 0);
505 }
506 canvas->restore();
507 canvas->translate(0, 120);
508 }
509}
510
511