blob: b182fb493c6931fb61807d25b2b18d5846109b56 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -04009#include "include/core/SkBitmap.h"
10#include "include/core/SkBlurTypes.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/core/SkCanvas.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040012#include "include/core/SkColor.h"
13#include "include/core/SkFilterQuality.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "include/core/SkImage.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040015#include "include/core/SkImageInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "include/core/SkMaskFilter.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040017#include "include/core/SkMatrix.h"
18#include "include/core/SkPaint.h"
19#include "include/core/SkPoint.h"
20#include "include/core/SkRect.h"
21#include "include/core/SkRefCnt.h"
22#include "include/core/SkScalar.h"
23#include "include/core/SkShader.h"
24#include "include/core/SkSize.h"
25#include "include/core/SkString.h"
26#include "include/core/SkSurface.h"
27#include "include/core/SkTileMode.h"
28#include "include/core/SkTypes.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050029#include "include/effects/SkGradientShader.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040030#include "include/gpu/GrContextOptions.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050031#include "include/private/SkTDArray.h"
32#include "src/core/SkBlurMask.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050033#include "tools/ToolUtils.h"
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000034
bsalomon5c1262d2015-11-09 10:06:06 -080035/** Holds either a bitmap or image to be rendered and a rect that indicates what part of the bitmap
36 or image should be tested by the GM. The area outside of the rect is present to check
37 for bleed due to filtering/blurring. */
38struct TestPixels {
39 enum Type {
40 kBitmap,
41 kImage
42 };
reed9ce9d672016-03-17 10:51:11 -070043 Type fType;
44 SkBitmap fBitmap;
45 sk_sp<SkImage> fImage;
46 SkIRect fRect; // The region of the bitmap/image that should be rendered.
bsalomon5c1262d2015-11-09 10:06:06 -080047};
reeda5517e22015-07-14 10:54:12 -070048
bsalomon5c1262d2015-11-09 10:06:06 -080049/** Creates a bitmap with two one-pixel rings around a checkerboard. The checkerboard is 2x2
50 logically where each check has as many pixels as is necessary to fill the interior. The rect
51 to draw is set to the checkerboard portion. */
52template<typename PIXEL_TYPE>
bsalomona2e08372016-07-13 14:50:17 -070053bool make_ringed_bitmap(TestPixels* result, int width, int height,
bsalomon5c1262d2015-11-09 10:06:06 -080054 SkColorType ct, SkAlphaType at,
55 PIXEL_TYPE outerRingColor, PIXEL_TYPE innerRingColor,
56 PIXEL_TYPE checkColor1, PIXEL_TYPE checkColor2) {
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +000057 SkASSERT(0 == width % 2 && 0 == height % 2);
bsalomon5c1262d2015-11-09 10:06:06 -080058 SkASSERT(width >= 6 && height >= 6);
skia.committer@gmail.comed000842013-11-09 07:02:23 +000059
bsalomon5c1262d2015-11-09 10:06:06 -080060 result->fType = TestPixels::kBitmap;
61 SkImageInfo info = SkImageInfo::Make(width, height, ct, at);
62 size_t rowBytes = SkAlign4(info.minRowBytes());
63 result->fBitmap.allocPixels(info, rowBytes);
64
65 PIXEL_TYPE* scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, 0);
66 for (int x = 0; x < width; ++x) {
67 scanline[x] = outerRingColor;
68 }
69 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, 1);
70 scanline[0] = outerRingColor;
71 for (int x = 1; x < width - 1; ++x) {
72 scanline[x] = innerRingColor;
73 }
74 scanline[width - 1] = outerRingColor;
75
76 for (int y = 2; y < height / 2; ++y) {
77 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, y);
78 scanline[0] = outerRingColor;
79 scanline[1] = innerRingColor;
80 for (int x = 2; x < width / 2; ++x) {
81 scanline[x] = checkColor1;
82 }
83 for (int x = width / 2; x < width - 2; ++x) {
84 scanline[x] = checkColor2;
85 }
86 scanline[width - 2] = innerRingColor;
87 scanline[width - 1] = outerRingColor;
88 }
89
90 for (int y = height / 2; y < height - 2; ++y) {
91 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, y);
92 scanline[0] = outerRingColor;
93 scanline[1] = innerRingColor;
94 for (int x = 2; x < width / 2; ++x) {
95 scanline[x] = checkColor2;
96 }
97 for (int x = width / 2; x < width - 2; ++x) {
98 scanline[x] = checkColor1;
99 }
100 scanline[width - 2] = innerRingColor;
101 scanline[width - 1] = outerRingColor;
102 }
103
104 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, height - 2);
105 scanline[0] = outerRingColor;
106 for (int x = 1; x < width - 1; ++x) {
107 scanline[x] = innerRingColor;
108 }
109 scanline[width - 1] = outerRingColor;
110
111 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, height - 1);
112 for (int x = 0; x < width; ++x) {
113 scanline[x] = outerRingColor;
114 }
115 result->fBitmap.setImmutable();
Mike Reed92b33352019-08-24 19:39:13 -0400116 result->fRect.setLTRB(2, 2, width - 2, height - 2);
bsalomon5c1262d2015-11-09 10:06:06 -0800117 return true;
118}
119
bsalomona2e08372016-07-13 14:50:17 -0700120/** Create a black and white checked bitmap with 2 1-pixel rings around the outside edge.
bsalomon5c1262d2015-11-09 10:06:06 -0800121 The inner ring is red and the outer ring is blue. */
bsalomona2e08372016-07-13 14:50:17 -0700122static bool make_ringed_color_bitmap(TestPixels* result, int width, int height) {
mtkleindbfd7ab2016-09-01 11:24:54 -0700123 const SkPMColor kBlue = SkPreMultiplyColor(SK_ColorBLUE);
124 const SkPMColor kRed = SkPreMultiplyColor(SK_ColorRED);
125 const SkPMColor kBlack = SkPreMultiplyColor(SK_ColorBLACK);
126 const SkPMColor kWhite = SkPreMultiplyColor(SK_ColorWHITE);
bsalomon48b24612016-08-25 06:45:29 -0700127 return make_ringed_bitmap<SkPMColor>(result, width, height, kN32_SkColorType,
bsalomon5c1262d2015-11-09 10:06:06 -0800128 kPremul_SkAlphaType, kBlue, kRed, kBlack, kWhite);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000129}
130
bsalomondf85a722015-11-04 04:23:45 -0800131/** 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 -0700132 checker board of 3/4 and 1/2. The inner checkers are large enough to fill the interior with
133 the 2x2 checker grid. */
bsalomona2e08372016-07-13 14:50:17 -0700134static bool make_ringed_alpha_bitmap(TestPixels* result, int width, int height) {
mtkleindbfd7ab2016-09-01 11:24:54 -0700135 constexpr uint8_t kZero = 0x00;
136 constexpr uint8_t kHalf = 0x80;
137 constexpr uint8_t k3Q = 0xC0;
138 constexpr uint8_t kOne = 0xFF;
bsalomona2e08372016-07-13 14:50:17 -0700139 return make_ringed_bitmap<uint8_t>(result, width, height, kAlpha_8_SkColorType,
bsalomon5c1262d2015-11-09 10:06:06 -0800140 kPremul_SkAlphaType, kZero, kOne, k3Q, kHalf);
141}
142
143/** Helper to reuse above functions to produce images rather than bmps */
144static void bmp_to_image(TestPixels* result) {
145 SkASSERT(TestPixels::kBitmap == result->fType);
reed9ce9d672016-03-17 10:51:11 -0700146 result->fImage = SkImage::MakeFromBitmap(result->fBitmap);
bsalomon5c1262d2015-11-09 10:06:06 -0800147 SkASSERT(result->fImage);
148 result->fType = TestPixels::kImage;
149 result->fBitmap.reset();
150}
151
152/** Color image case. */
bsalomona2e08372016-07-13 14:50:17 -0700153bool make_ringed_color_image(TestPixels* result, int width, int height) {
154 if (make_ringed_color_bitmap(result, width, height)) {
bsalomon5c1262d2015-11-09 10:06:06 -0800155 bmp_to_image(result);
156 return true;
157 }
158 return false;
159}
160
161/** Alpha image case. */
bsalomona2e08372016-07-13 14:50:17 -0700162bool make_ringed_alpha_image(TestPixels* result, int width, int height) {
163 if (make_ringed_alpha_bitmap(result, width, height)) {
bsalomon5c1262d2015-11-09 10:06:06 -0800164 bmp_to_image(result);
165 return true;
166 }
167 return false;
168}
169
reed2ad1aa62016-03-09 09:50:50 -0800170static sk_sp<SkShader> make_shader() {
mtkleindbfd7ab2016-09-01 11:24:54 -0700171 constexpr SkPoint pts[] = { {0, 0}, {20, 20} };
172 constexpr SkColor colors[] = { SK_ColorGREEN, SK_ColorYELLOW };
Mike Reedfae8fce2019-04-03 10:27:45 -0400173 return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kMirror);
bsalomon9003d1e2015-10-23 11:13:01 -0700174}
175
reed2ad1aa62016-03-09 09:50:50 -0800176static sk_sp<SkShader> make_null_shader() { return nullptr; }
bsalomon9003d1e2015-10-23 11:13:01 -0700177
178enum BleedTest {
179 kUseBitmap_BleedTest,
180 kUseImage_BleedTest,
181 kUseAlphaBitmap_BleedTest,
182 kUseAlphaImage_BleedTest,
183 kUseAlphaBitmapShader_BleedTest,
184 kUseAlphaImageShader_BleedTest,
185};
186
187const struct {
188 const char* fName;
bsalomona2e08372016-07-13 14:50:17 -0700189 bool (*fPixelMaker)(TestPixels* result, int width, int height);
reed2ad1aa62016-03-09 09:50:50 -0800190 sk_sp<SkShader> (*fShaderMaker)();
bsalomon9003d1e2015-10-23 11:13:01 -0700191} gBleedRec[] = {
bsalomon5c1262d2015-11-09 10:06:06 -0800192 { "bleed", make_ringed_color_bitmap, make_null_shader },
bsalomon5c1262d2015-11-09 10:06:06 -0800193 { "bleed_image", make_ringed_color_image, make_null_shader },
194 { "bleed_alpha_bmp", make_ringed_alpha_bitmap, make_null_shader },
bsalomon5c1262d2015-11-09 10:06:06 -0800195 { "bleed_alpha_image", make_ringed_alpha_image, make_null_shader },
196 { "bleed_alpha_bmp_shader", make_ringed_alpha_bitmap, make_shader },
bsalomon5c1262d2015-11-09 10:06:06 -0800197 { "bleed_alpha_image_shader", make_ringed_alpha_image, make_shader },
bsalomon9003d1e2015-10-23 11:13:01 -0700198};
199
bsalomon5c1262d2015-11-09 10:06:06 -0800200/** This GM exercises the behavior of the drawBitmapRect & drawImageRect calls. Specifically their
201 handling of :
202 - SrcRectConstraint(bleed vs.no - bleed)
203 - handling of the sub - region feature(area - of - interest) of drawBitmap*
204 - handling of 8888 vs. A8 (including presence of a shader in the A8 case).
bsalomon5c1262d2015-11-09 10:06:06 -0800205 In particular, we should never see the padding outside of an SkBitmap's sub - region (green for
206 8888, 1/4 for alpha). In some instances we can see the two outer rings outside of the area o
207 interest (i.e., the inner four checks) due to AA or filtering if allowed by the
208 SrcRectConstraint.
209*/
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000210class BleedGM : public skiagm::GM {
211public:
bsalomona2e08372016-07-13 14:50:17 -0700212 BleedGM(BleedTest bt) : fBT(bt){}
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000213
214protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000215
mtklein36352bf2015-03-25 18:17:31 -0700216 SkString onShortName() override {
reeda5517e22015-07-14 10:54:12 -0700217 return SkString(gBleedRec[fBT].fName);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000218 }
219
mtklein36352bf2015-03-25 18:17:31 -0700220 SkISize onISize() override {
bsalomonf57ef1c2015-11-04 04:36:12 -0800221 return SkISize::Make(1200, 1080);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000222 }
223
bsalomon5c1262d2015-11-09 10:06:06 -0800224 void drawPixels(SkCanvas* canvas, const TestPixels& pixels, const SkRect& src,
225 const SkRect& dst, const SkPaint* paint,
226 SkCanvas::SrcRectConstraint constraint) {
227 if (TestPixels::kBitmap == pixels.fType) {
228 canvas->drawBitmapRect(pixels.fBitmap, src, dst, paint, constraint);
229 } else {
reed9ce9d672016-03-17 10:51:11 -0700230 canvas->drawImageRect(pixels.fImage.get(), src, dst, paint, constraint);
bsalomon5c1262d2015-11-09 10:06:06 -0800231 }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000232 }
233
bsalomon5c1262d2015-11-09 10:06:06 -0800234 // Draw the area of interest of the small image
bsalomon9003d1e2015-10-23 11:13:01 -0700235 void drawCase1(SkCanvas* canvas, int transX, int transY, bool aa,
reeda5517e22015-07-14 10:54:12 -0700236 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800237
238 SkRect src = SkRect::Make(fSmallTestPixels.fRect);
reeda5517e22015-07-14 10:54:12 -0700239 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
240 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000241
242 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700243 paint.setFilterQuality(filter);
bsalomon9003d1e2015-10-23 11:13:01 -0700244 paint.setShader(fShader);
245 paint.setColor(SK_ColorBLUE);
246 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000247
bsalomon5c1262d2015-11-09 10:06:06 -0800248 this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000249 }
250
bsalomon5c1262d2015-11-09 10:06:06 -0800251 // Draw the area of interest of the large image
bsalomon9003d1e2015-10-23 11:13:01 -0700252 void drawCase2(SkCanvas* canvas, int transX, int transY, bool aa,
reeda5517e22015-07-14 10:54:12 -0700253 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800254 SkRect src = SkRect::Make(fBigTestPixels.fRect);
reeda5517e22015-07-14 10:54:12 -0700255 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
256 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000257
258 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700259 paint.setFilterQuality(filter);
bsalomon9003d1e2015-10-23 11:13:01 -0700260 paint.setShader(fShader);
261 paint.setColor(SK_ColorBLUE);
262 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000263
bsalomon5c1262d2015-11-09 10:06:06 -0800264 this->drawPixels(canvas, fBigTestPixels, src, dst, &paint, constraint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000265 }
266
bsalomon5c1262d2015-11-09 10:06:06 -0800267 // Draw upper-left 1/4 of the area of interest of the large image
bsalomon9003d1e2015-10-23 11:13:01 -0700268 void drawCase3(SkCanvas* canvas, int transX, int transY, bool aa,
reeda5517e22015-07-14 10:54:12 -0700269 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800270 SkRect src = SkRect::MakeXYWH(SkIntToScalar(fBigTestPixels.fRect.fLeft),
271 SkIntToScalar(fBigTestPixels.fRect.fTop),
272 fBigTestPixels.fRect.width()/2.f,
273 fBigTestPixels.fRect.height()/2.f);
reeda5517e22015-07-14 10:54:12 -0700274 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
275 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000276
277 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700278 paint.setFilterQuality(filter);
bsalomon9003d1e2015-10-23 11:13:01 -0700279 paint.setShader(fShader);
280 paint.setColor(SK_ColorBLUE);
281 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000282
bsalomon5c1262d2015-11-09 10:06:06 -0800283 this->drawPixels(canvas, fBigTestPixels, src, dst, &paint, constraint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000284 }
285
bsalomon5c1262d2015-11-09 10:06:06 -0800286 // Draw the area of interest of the small image with a normal blur
bsalomon9003d1e2015-10-23 11:13:01 -0700287 void drawCase4(SkCanvas* canvas, int transX, int transY, bool aa,
reeda5517e22015-07-14 10:54:12 -0700288 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800289 SkRect src = SkRect::Make(fSmallTestPixels.fRect);
reeda5517e22015-07-14 10:54:12 -0700290 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
291 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000292
293 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700294 paint.setFilterQuality(filter);
Mike Reed1be1f8d2018-03-14 13:01:17 -0400295 paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle,
reedefdfd512016-04-04 10:02:58 -0700296 SkBlurMask::ConvertRadiusToSigma(3)));
bsalomon9003d1e2015-10-23 11:13:01 -0700297 paint.setShader(fShader);
298 paint.setColor(SK_ColorBLUE);
299 paint.setAntiAlias(aa);
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000300
bsalomon5c1262d2015-11-09 10:06:06 -0800301 this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000302 }
303
bsalomon5c1262d2015-11-09 10:06:06 -0800304 // Draw the area of interest of the small image with a outer blur
bsalomonf57ef1c2015-11-04 04:36:12 -0800305 void drawCase5(SkCanvas* canvas, int transX, int transY, bool aa,
306 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800307 SkRect src = SkRect::Make(fSmallTestPixels.fRect);
bsalomonf57ef1c2015-11-04 04:36:12 -0800308 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
309 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
310
311 SkPaint paint;
312 paint.setFilterQuality(filter);
Mike Reed1be1f8d2018-03-14 13:01:17 -0400313 paint.setMaskFilter(SkMaskFilter::MakeBlur(kOuter_SkBlurStyle,
reedefdfd512016-04-04 10:02:58 -0700314 SkBlurMask::ConvertRadiusToSigma(7)));
bsalomonf57ef1c2015-11-04 04:36:12 -0800315 paint.setShader(fShader);
316 paint.setColor(SK_ColorBLUE);
317 paint.setAntiAlias(aa);
318
bsalomon5c1262d2015-11-09 10:06:06 -0800319 this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
bsalomonf57ef1c2015-11-04 04:36:12 -0800320 }
321
bsalomona2e08372016-07-13 14:50:17 -0700322 void onOnceBeforeDraw() override {
323 SkAssertResult(gBleedRec[fBT].fPixelMaker(&fSmallTestPixels, kSmallSize, kSmallSize));
324 SkAssertResult(gBleedRec[fBT].fPixelMaker(&fBigTestPixels, 2 * kMaxTileSize,
325 2 * kMaxTileSize));
326 }
327
mtklein36352bf2015-03-25 18:17:31 -0700328 void onDraw(SkCanvas* canvas) override {
reed2ad1aa62016-03-09 09:50:50 -0800329 fShader = gBleedRec[fBT].fShaderMaker();
bsalomon5c1262d2015-11-09 10:06:06 -0800330
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000331 canvas->clear(SK_ColorGRAY);
bsalomon9003d1e2015-10-23 11:13:01 -0700332 SkTDArray<SkMatrix> matrices;
333 // Draw with identity
334 *matrices.append() = SkMatrix::I();
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000335
bsalomon9003d1e2015-10-23 11:13:01 -0700336 // Draw with rotation and scale down in x, up in y.
337 SkMatrix m;
mtkleindbfd7ab2016-09-01 11:24:54 -0700338 constexpr SkScalar kBottom = SkIntToScalar(kRow4Y + kBlockSize + kBlockSpacing);
bsalomon9003d1e2015-10-23 11:13:01 -0700339 m.setTranslate(0, kBottom);
340 m.preRotate(15.f, 0, kBottom + kBlockSpacing);
341 m.preScale(0.71f, 1.22f);
342 *matrices.append() = m;
343
344 // Align the next set with the middle of the previous in y, translated to the right in x.
345 SkPoint corners[] = {{0, 0}, { 0, kBottom }, { kWidth, kBottom }, {kWidth, 0} };
346 matrices[matrices.count()-1].mapPoints(corners, 4);
347 SkScalar y = (corners[0].fY + corners[1].fY + corners[2].fY + corners[3].fY) / 4;
348 SkScalar x = SkTMax(SkTMax(corners[0].fX, corners[1].fX),
349 SkTMax(corners[2].fX, corners[3].fX));
350 m.setTranslate(x, y);
351 m.preScale(0.2f, 0.2f);
352 *matrices.append() = m;
353
354 SkScalar maxX = 0;
355 for (int antiAlias = 0; antiAlias < 2; ++antiAlias) {
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000356 canvas->save();
bsalomon9003d1e2015-10-23 11:13:01 -0700357 canvas->translate(maxX, 0);
358 for (int m = 0; m < matrices.count(); ++m) {
359 canvas->save();
360 canvas->concat(matrices[m]);
361 bool aa = SkToBool(antiAlias);
362
363 // First draw a column with no bleeding and no filtering
364 this->drawCase1(canvas, kCol0X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
365 this->drawCase2(canvas, kCol0X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
366 this->drawCase3(canvas, kCol0X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
367 this->drawCase4(canvas, kCol0X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800368 this->drawCase5(canvas, kCol0X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700369
370 // Then draw a column with no bleeding and low filtering
371 this->drawCase1(canvas, kCol1X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
372 this->drawCase2(canvas, kCol1X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
373 this->drawCase3(canvas, kCol1X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
374 this->drawCase4(canvas, kCol1X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800375 this->drawCase5(canvas, kCol1X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700376
377 // Then draw a column with no bleeding and high filtering
378 this->drawCase1(canvas, kCol2X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
379 this->drawCase2(canvas, kCol2X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
380 this->drawCase3(canvas, kCol2X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
381 this->drawCase4(canvas, kCol2X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800382 this->drawCase5(canvas, kCol2X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700383
384 // Then draw a column with bleeding and no filtering (bleed should have no effect w/out blur)
385 this->drawCase1(canvas, kCol3X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
386 this->drawCase2(canvas, kCol3X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
387 this->drawCase3(canvas, kCol3X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
388 this->drawCase4(canvas, kCol3X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800389 this->drawCase5(canvas, kCol3X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700390
391 // Then draw a column with bleeding and low filtering
392 this->drawCase1(canvas, kCol4X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
393 this->drawCase2(canvas, kCol4X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
394 this->drawCase3(canvas, kCol4X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
395 this->drawCase4(canvas, kCol4X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800396 this->drawCase5(canvas, kCol4X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700397
398 // Finally draw a column with bleeding and high filtering
399 this->drawCase1(canvas, kCol5X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
400 this->drawCase2(canvas, kCol5X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
401 this->drawCase3(canvas, kCol5X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
402 this->drawCase4(canvas, kCol5X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800403 this->drawCase5(canvas, kCol5X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700404
405 SkPoint corners[] = { { 0, 0 },{ 0, kBottom },{ kWidth, kBottom },{ kWidth, 0 } };
406 matrices[m].mapPoints(corners, 4);
407 SkScalar x = kBlockSize + SkTMax(SkTMax(corners[0].fX, corners[1].fX),
408 SkTMax(corners[2].fX, corners[3].fX));
409 maxX = SkTMax(maxX, x);
410 canvas->restore();
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000411 }
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000412 canvas->restore();
413 }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000414 }
415
bsalomon4ee6bd82015-05-27 13:23:23 -0700416 void modifyGrContextOptions(GrContextOptions* options) override {
bsalomon8c07b7a2015-11-02 11:36:52 -0800417 options->fMaxTileSizeOverride = kMaxTileSize;
bsalomon4ee6bd82015-05-27 13:23:23 -0700418 }
bsalomon4ee6bd82015-05-27 13:23:23 -0700419
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000420private:
mtkleindbfd7ab2016-09-01 11:24:54 -0700421 static constexpr int kBlockSize = 70;
422 static constexpr int kBlockSpacing = 12;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000423
mtkleindbfd7ab2016-09-01 11:24:54 -0700424 static constexpr int kCol0X = kBlockSpacing;
425 static constexpr int kCol1X = 2*kBlockSpacing + kBlockSize;
426 static constexpr int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
427 static constexpr int kCol3X = 4*kBlockSpacing + 3*kBlockSize;
428 static constexpr int kCol4X = 5*kBlockSpacing + 4*kBlockSize;
429 static constexpr int kCol5X = 6*kBlockSpacing + 5*kBlockSize;
430 static constexpr int kWidth = 7*kBlockSpacing + 6*kBlockSize;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000431
mtkleindbfd7ab2016-09-01 11:24:54 -0700432 static constexpr int kRow0Y = kBlockSpacing;
433 static constexpr int kRow1Y = 2*kBlockSpacing + kBlockSize;
434 static constexpr int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
435 static constexpr int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
436 static constexpr int kRow4Y = 5*kBlockSpacing + 4*kBlockSize;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000437
mtkleindbfd7ab2016-09-01 11:24:54 -0700438 static constexpr int kSmallSize = 6;
439 static constexpr int kMaxTileSize = 32;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000440
reed2ad1aa62016-03-09 09:50:50 -0800441 TestPixels fBigTestPixels;
442 TestPixels fSmallTestPixels;
bsalomon9003d1e2015-10-23 11:13:01 -0700443
reed2ad1aa62016-03-09 09:50:50 -0800444 sk_sp<SkShader> fShader;
bsalomon9003d1e2015-10-23 11:13:01 -0700445
reed2ad1aa62016-03-09 09:50:50 -0800446 const BleedTest fBT;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000447
448 typedef GM INHERITED;
449};
450
bsalomon9c586542015-11-02 12:33:21 -0800451
reeda5517e22015-07-14 10:54:12 -0700452DEF_GM( return new BleedGM(kUseBitmap_BleedTest); )
453DEF_GM( return new BleedGM(kUseImage_BleedTest); )
bsalomon9003d1e2015-10-23 11:13:01 -0700454DEF_GM( return new BleedGM(kUseAlphaBitmap_BleedTest); )
455DEF_GM( return new BleedGM(kUseAlphaImage_BleedTest); )
bsalomon9c586542015-11-02 12:33:21 -0800456DEF_GM( return new BleedGM(kUseAlphaBitmapShader_BleedTest); )
bsalomon9c586542015-11-02 12:33:21 -0800457DEF_GM( return new BleedGM(kUseAlphaImageShader_BleedTest); )
reed2adecda2016-07-25 08:11:58 -0700458
459///////////////////////////////////////////////////////////////////////////////////////////////////
reed2adecda2016-07-25 08:11:58 -0700460
reed2adecda2016-07-25 08:11:58 -0700461// Construct an image and return the inner "src" rect. Build the image such that the interior is
462// blue, with a margin of blue (2px) but then an outer margin of red.
463//
464// Show that kFast_SrcRectConstraint sees even the red margin (due to mipmapping) when the image
465// is scaled down far enough.
466//
467static sk_sp<SkImage> make_image(SkCanvas* canvas, SkRect* srcR) {
egdaniel26318c92016-07-26 08:26:46 -0700468 // Intentially making the size a power of 2 to avoid the noise from how different GPUs will
469 // produce different mipmap filtering when we have an odd sized texture.
470 const int N = 10 + 2 + 8 + 2 + 10;
reed2adecda2016-07-25 08:11:58 -0700471 SkImageInfo info = SkImageInfo::MakeN32Premul(N, N);
Mike Kleinea3f0142019-03-20 11:12:10 -0500472 auto surface = ToolUtils::makeSurface(canvas, info);
reed2adecda2016-07-25 08:11:58 -0700473 SkCanvas* c = surface->getCanvas();
474 SkRect r = SkRect::MakeIWH(info.width(), info.height());
475 SkPaint paint;
476
477 paint.setColor(SK_ColorRED);
478 c->drawRect(r, paint);
egdaniel26318c92016-07-26 08:26:46 -0700479 r.inset(10, 10);
reed2adecda2016-07-25 08:11:58 -0700480 paint.setColor(SK_ColorBLUE);
481 c->drawRect(r, paint);
482
483 *srcR = r.makeInset(2, 2);
484 return surface->makeImageSnapshot();
485}
486
487DEF_SIMPLE_GM(bleed_downscale, canvas, 360, 240) {
488 SkRect src;
489 sk_sp<SkImage> img = make_image(canvas, &src);
490 SkPaint paint;
491
492 canvas->translate(10, 10);
493
494 const SkCanvas::SrcRectConstraint constraints[] = {
495 SkCanvas::kStrict_SrcRectConstraint, SkCanvas::kFast_SrcRectConstraint
496 };
497 const SkFilterQuality qualities[] = {
498 kNone_SkFilterQuality, kLow_SkFilterQuality, kMedium_SkFilterQuality
499 };
500 for (auto constraint : constraints) {
501 canvas->save();
502 for (auto quality : qualities) {
503 paint.setFilterQuality(quality);
Mike Kleinea3f0142019-03-20 11:12:10 -0500504 auto surf = ToolUtils::makeSurface(canvas, SkImageInfo::MakeN32Premul(1, 1));
reed2adecda2016-07-25 08:11:58 -0700505 surf->getCanvas()->drawImageRect(img, src, SkRect::MakeWH(1, 1), &paint, constraint);
506 // now blow up the 1 pixel result
507 canvas->drawImageRect(surf->makeImageSnapshot(), SkRect::MakeWH(100, 100), nullptr);
508 canvas->translate(120, 0);
509 }
510 canvas->restore();
511 canvas->translate(0, 120);
512 }
513}
514
515