blob: 8125319c855307120a59b32840dd6f3f90c2e249 [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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/core/SkImage.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040014#include "include/core/SkImageInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "include/core/SkMaskFilter.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040016#include "include/core/SkMatrix.h"
17#include "include/core/SkPaint.h"
18#include "include/core/SkPoint.h"
19#include "include/core/SkRect.h"
20#include "include/core/SkRefCnt.h"
21#include "include/core/SkScalar.h"
22#include "include/core/SkShader.h"
23#include "include/core/SkSize.h"
24#include "include/core/SkString.h"
25#include "include/core/SkSurface.h"
26#include "include/core/SkTileMode.h"
27#include "include/core/SkTypes.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040028#include "include/gpu/GrContextOptions.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050029#include "include/private/SkTDArray.h"
30#include "src/core/SkBlurMask.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050031#include "tools/ToolUtils.h"
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000032
Brian Salomon6ef29332020-05-15 09:52:29 -040033/** Creates an image with two one-pixel wide borders around a checkerboard. The checkerboard is 2x2
34 checks where each check has as many pixels as is necessary to fill the interior. It returns
35 the image and a src rect that bounds the checkerboard portion. */
Mike Reed8d29ab62021-01-23 18:10:39 -050036std::tuple<sk_sp<SkImage>, SkRect> make_ringed_image(int width, int height) {
reeda5517e22015-07-14 10:54:12 -070037
Brian Salomon6ef29332020-05-15 09:52:29 -040038 // These are kRGBA_8888_SkColorType values.
39 static constexpr uint32_t kOuterRingColor = 0xFFFF0000,
40 kInnerRingColor = 0xFF0000FF,
41 kCheckColor1 = 0xFF000000,
42 kCheckColor2 = 0xFFFFFFFF;
43
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
Brian Salomon6ef29332020-05-15 09:52:29 -040047 SkImageInfo info = SkImageInfo::Make(width, height, kRGBA_8888_SkColorType,
48 kPremul_SkAlphaType);
bsalomon5c1262d2015-11-09 10:06:06 -080049 size_t rowBytes = SkAlign4(info.minRowBytes());
Brian Salomon6ef29332020-05-15 09:52:29 -040050 SkBitmap bitmap;
51 bitmap.allocPixels(info, rowBytes);
bsalomon5c1262d2015-11-09 10:06:06 -080052
Brian Salomon6ef29332020-05-15 09:52:29 -040053 uint32_t* scanline = bitmap.getAddr32(0, 0);
bsalomon5c1262d2015-11-09 10:06:06 -080054 for (int x = 0; x < width; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -040055 scanline[x] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080056 }
Brian Salomon6ef29332020-05-15 09:52:29 -040057 scanline = bitmap.getAddr32(0, 1);
58 scanline[0] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080059 for (int x = 1; x < width - 1; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -040060 scanline[x] = kInnerRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080061 }
Brian Salomon6ef29332020-05-15 09:52:29 -040062 scanline[width - 1] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080063
64 for (int y = 2; y < height / 2; ++y) {
Brian Salomon6ef29332020-05-15 09:52:29 -040065 scanline = bitmap.getAddr32(0, y);
66 scanline[0] = kOuterRingColor;
67 scanline[1] = kInnerRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080068 for (int x = 2; x < width / 2; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -040069 scanline[x] = kCheckColor1;
bsalomon5c1262d2015-11-09 10:06:06 -080070 }
71 for (int x = width / 2; x < width - 2; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -040072 scanline[x] = kCheckColor2;
bsalomon5c1262d2015-11-09 10:06:06 -080073 }
Brian Salomon6ef29332020-05-15 09:52:29 -040074 scanline[width - 2] = kInnerRingColor;
75 scanline[width - 1] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080076 }
77
78 for (int y = height / 2; y < height - 2; ++y) {
Brian Salomon6ef29332020-05-15 09:52:29 -040079 scanline = bitmap.getAddr32(0, y);
80 scanline[0] = kOuterRingColor;
81 scanline[1] = kInnerRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080082 for (int x = 2; x < width / 2; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -040083 scanline[x] = kCheckColor2;
bsalomon5c1262d2015-11-09 10:06:06 -080084 }
85 for (int x = width / 2; x < width - 2; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -040086 scanline[x] = kCheckColor1;
bsalomon5c1262d2015-11-09 10:06:06 -080087 }
Brian Salomon6ef29332020-05-15 09:52:29 -040088 scanline[width - 2] = kInnerRingColor;
89 scanline[width - 1] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080090 }
91
Brian Salomon6ef29332020-05-15 09:52:29 -040092 scanline = bitmap.getAddr32(0, height - 2);
93 scanline[0] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080094 for (int x = 1; x < width - 1; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -040095 scanline[x] = kInnerRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080096 }
Brian Salomon6ef29332020-05-15 09:52:29 -040097 scanline[width - 1] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080098
Brian Salomon6ef29332020-05-15 09:52:29 -040099 scanline = bitmap.getAddr32(0, height - 1);
bsalomon5c1262d2015-11-09 10:06:06 -0800100 for (int x = 0; x < width; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -0400101 scanline[x] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -0800102 }
Brian Salomon6ef29332020-05-15 09:52:29 -0400103 bitmap.setImmutable();
Mike Reed8d29ab62021-01-23 18:10:39 -0500104 return {bitmap.asImage(), SkRect::Make({2, 2, width - 2, height - 2})};
bsalomon5c1262d2015-11-09 10:06:06 -0800105}
106
Brian Salomon6ef29332020-05-15 09:52:29 -0400107/**
Brian Salomonca769202020-05-18 16:40:59 -0400108 * These GMs exercise the behavior of the drawImageRect and its SrcRectConstraint parameter. They
109 * tests various matrices, filter qualities, and interaction with mask filters. They also exercise
Brian Salomon6ef29332020-05-15 09:52:29 -0400110 * the tiling image draws of SkGpuDevice by overriding the maximum texture size of the GrContext.
111 */
Brian Salomonca769202020-05-18 16:40:59 -0400112class SrcRectConstraintGM : public skiagm::GM {
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000113public:
John Stilesd20a1342020-05-26 10:38:24 -0400114 SrcRectConstraintGM(const char* shortName, SkCanvas::SrcRectConstraint constraint, bool batch)
115 : fShortName(shortName)
116 , fConstraint(constraint)
Brian Salomon010bb462021-01-29 14:42:38 -0500117 , fBatch(batch) {
118 // Make sure GPU SkSurfaces can be created for this GM.
119 SkASSERT(this->onISize().width() <= kMaxTextureSize &&
120 this->onISize().height() <= kMaxTextureSize);
121 }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000122
123protected:
John Stilesd20a1342020-05-26 10:38:24 -0400124 SkString onShortName() override { return fShortName; }
Brian Salomonca769202020-05-18 16:40:59 -0400125 SkISize onISize() override { return SkISize::Make(800, 1000); }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000126
Mike Reed8d29ab62021-01-23 18:10:39 -0500127 void drawImage(SkCanvas* canvas, sk_sp<SkImage> image, SkRect srcRect, SkRect dstRect,
128 const SkSamplingOptions& sampling, SkPaint* paint) {
John Stilesd20a1342020-05-26 10:38:24 -0400129 if (fBatch) {
130 SkCanvas::ImageSetEntry imageSetEntry[1];
131 imageSetEntry[0].fImage = image;
Mike Reed8d29ab62021-01-23 18:10:39 -0500132 imageSetEntry[0].fSrcRect = srcRect;
John Stilesd20a1342020-05-26 10:38:24 -0400133 imageSetEntry[0].fDstRect = dstRect;
134 imageSetEntry[0].fAAFlags = paint->isAntiAlias() ? SkCanvas::kAll_QuadAAFlags
135 : SkCanvas::kNone_QuadAAFlags;
136 canvas->experimental_DrawEdgeAAImageSet(imageSetEntry, SK_ARRAY_COUNT(imageSetEntry),
137 /*dstClips=*/nullptr,
138 /*preViewMatrices=*/nullptr,
Mike Reed8d29ab62021-01-23 18:10:39 -0500139 sampling, paint, fConstraint);
John Stilesd20a1342020-05-26 10:38:24 -0400140 } else {
Mike Reed8d29ab62021-01-23 18:10:39 -0500141 canvas->drawImageRect(image.get(), srcRect, dstRect, sampling, paint, fConstraint);
John Stilesd20a1342020-05-26 10:38:24 -0400142 }
143 }
144
bsalomon5c1262d2015-11-09 10:06:06 -0800145 // Draw the area of interest of the small image
Mike Reed8d29ab62021-01-23 18:10:39 -0500146 void drawCase1(SkCanvas* canvas, int transX, int transY, bool aa,
147 const SkSamplingOptions& sampling) {
reeda5517e22015-07-14 10:54:12 -0700148 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
149 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000150
151 SkPaint paint;
bsalomon9003d1e2015-10-23 11:13:01 -0700152 paint.setColor(SK_ColorBLUE);
153 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000154
Mike Reed8d29ab62021-01-23 18:10:39 -0500155 drawImage(canvas, fSmallImage, fSmallSrcRect, dst, sampling, &paint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000156 }
157
bsalomon5c1262d2015-11-09 10:06:06 -0800158 // Draw the area of interest of the large image
Mike Reed8d29ab62021-01-23 18:10:39 -0500159 void drawCase2(SkCanvas* canvas, int transX, int transY, bool aa,
160 const SkSamplingOptions& sampling) {
reeda5517e22015-07-14 10:54:12 -0700161 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
162 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000163
164 SkPaint paint;
bsalomon9003d1e2015-10-23 11:13:01 -0700165 paint.setColor(SK_ColorBLUE);
166 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000167
Mike Reed8d29ab62021-01-23 18:10:39 -0500168 drawImage(canvas, fBigImage, fBigSrcRect, dst, sampling, &paint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000169 }
170
bsalomon5c1262d2015-11-09 10:06:06 -0800171 // Draw upper-left 1/4 of the area of interest of the large image
Mike Reed8d29ab62021-01-23 18:10:39 -0500172 void drawCase3(SkCanvas* canvas, int transX, int transY, bool aa,
173 const SkSamplingOptions& sampling) {
174 SkRect src = SkRect::MakeXYWH(fBigSrcRect.fLeft,
175 fBigSrcRect.fTop,
176 fBigSrcRect.width()/2,
177 fBigSrcRect.height()/2);
reeda5517e22015-07-14 10:54:12 -0700178 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
179 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000180
181 SkPaint paint;
bsalomon9003d1e2015-10-23 11:13:01 -0700182 paint.setColor(SK_ColorBLUE);
183 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000184
Mike Reed8d29ab62021-01-23 18:10:39 -0500185 drawImage(canvas, fBigImage, src, dst, sampling, &paint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000186 }
187
bsalomon5c1262d2015-11-09 10:06:06 -0800188 // Draw the area of interest of the small image with a normal blur
Mike Reed8d29ab62021-01-23 18:10:39 -0500189 void drawCase4(SkCanvas* canvas, int transX, int transY, bool aa,
190 const SkSamplingOptions& sampling) {
reeda5517e22015-07-14 10:54:12 -0700191 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
192 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000193
194 SkPaint paint;
Mike Reed1be1f8d2018-03-14 13:01:17 -0400195 paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle,
reedefdfd512016-04-04 10:02:58 -0700196 SkBlurMask::ConvertRadiusToSigma(3)));
bsalomon9003d1e2015-10-23 11:13:01 -0700197 paint.setColor(SK_ColorBLUE);
198 paint.setAntiAlias(aa);
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000199
Mike Reed8d29ab62021-01-23 18:10:39 -0500200 drawImage(canvas, fSmallImage, fSmallSrcRect, dst, sampling, &paint);
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000201 }
202
bsalomon5c1262d2015-11-09 10:06:06 -0800203 // Draw the area of interest of the small image with a outer blur
Mike Reed8d29ab62021-01-23 18:10:39 -0500204 void drawCase5(SkCanvas* canvas, int transX, int transY, bool aa,
205 const SkSamplingOptions& sampling) {
bsalomonf57ef1c2015-11-04 04:36:12 -0800206 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
207 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
208
209 SkPaint paint;
Mike Reed1be1f8d2018-03-14 13:01:17 -0400210 paint.setMaskFilter(SkMaskFilter::MakeBlur(kOuter_SkBlurStyle,
reedefdfd512016-04-04 10:02:58 -0700211 SkBlurMask::ConvertRadiusToSigma(7)));
bsalomonf57ef1c2015-11-04 04:36:12 -0800212 paint.setColor(SK_ColorBLUE);
213 paint.setAntiAlias(aa);
214
Mike Reed8d29ab62021-01-23 18:10:39 -0500215 drawImage(canvas, fSmallImage, fSmallSrcRect, dst, sampling, &paint);
bsalomonf57ef1c2015-11-04 04:36:12 -0800216 }
217
bsalomona2e08372016-07-13 14:50:17 -0700218 void onOnceBeforeDraw() override {
Brian Salomon010bb462021-01-29 14:42:38 -0500219 std::tie(fBigImage, fBigSrcRect) = make_ringed_image(2*kMaxTextureSize, 2*kMaxTextureSize);
Brian Salomon6ef29332020-05-15 09:52:29 -0400220 std::tie(fSmallImage, fSmallSrcRect) = make_ringed_image(kSmallSize, kSmallSize);
bsalomona2e08372016-07-13 14:50:17 -0700221 }
222
mtklein36352bf2015-03-25 18:17:31 -0700223 void onDraw(SkCanvas* canvas) override {
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000224 canvas->clear(SK_ColorGRAY);
John Stilescbe4e282020-06-01 10:38:31 -0400225 std::vector<SkMatrix> matrices;
bsalomon9003d1e2015-10-23 11:13:01 -0700226 // Draw with identity
John Stilescbe4e282020-06-01 10:38:31 -0400227 matrices.push_back(SkMatrix::I());
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000228
bsalomon9003d1e2015-10-23 11:13:01 -0700229 // Draw with rotation and scale down in x, up in y.
230 SkMatrix m;
mtkleindbfd7ab2016-09-01 11:24:54 -0700231 constexpr SkScalar kBottom = SkIntToScalar(kRow4Y + kBlockSize + kBlockSpacing);
bsalomon9003d1e2015-10-23 11:13:01 -0700232 m.setTranslate(0, kBottom);
233 m.preRotate(15.f, 0, kBottom + kBlockSpacing);
234 m.preScale(0.71f, 1.22f);
John Stilescbe4e282020-06-01 10:38:31 -0400235 matrices.push_back(m);
bsalomon9003d1e2015-10-23 11:13:01 -0700236
237 // Align the next set with the middle of the previous in y, translated to the right in x.
John Stilescbe4e282020-06-01 10:38:31 -0400238 SkPoint corners[] = {{0, 0}, {0, kBottom}, {kWidth, kBottom}, {kWidth, 0}};
239 matrices.back().mapPoints(corners, 4);
bsalomon9003d1e2015-10-23 11:13:01 -0700240 SkScalar y = (corners[0].fY + corners[1].fY + corners[2].fY + corners[3].fY) / 4;
John Stilescbe4e282020-06-01 10:38:31 -0400241 SkScalar x = std::max({corners[0].fX, corners[1].fX, corners[2].fX, corners[3].fX});
bsalomon9003d1e2015-10-23 11:13:01 -0700242 m.setTranslate(x, y);
243 m.preScale(0.2f, 0.2f);
John Stilescbe4e282020-06-01 10:38:31 -0400244 matrices.push_back(m);
bsalomon9003d1e2015-10-23 11:13:01 -0700245
Mike Reed8d29ab62021-01-23 18:10:39 -0500246 const SkSamplingOptions none(SkFilterMode::kNearest);
247 const SkSamplingOptions low(SkFilterMode::kLinear);
Mike Reedf3ac2af2021-02-05 12:55:38 -0500248 const SkSamplingOptions high(SkCubicResampler::Mitchell());
Mike Reed8d29ab62021-01-23 18:10:39 -0500249
bsalomon9003d1e2015-10-23 11:13:01 -0700250 SkScalar maxX = 0;
John Stilescbe4e282020-06-01 10:38:31 -0400251 for (bool antiAlias : {false, true}) {
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000252 canvas->save();
bsalomon9003d1e2015-10-23 11:13:01 -0700253 canvas->translate(maxX, 0);
John Stilescbe4e282020-06-01 10:38:31 -0400254 for (const SkMatrix& matrix : matrices) {
bsalomon9003d1e2015-10-23 11:13:01 -0700255 canvas->save();
John Stilescbe4e282020-06-01 10:38:31 -0400256 canvas->concat(matrix);
bsalomon9003d1e2015-10-23 11:13:01 -0700257
Brian Salomonca769202020-05-18 16:40:59 -0400258 // First draw a column with no filtering
Mike Reed8d29ab62021-01-23 18:10:39 -0500259 this->drawCase1(canvas, kCol0X, kRow0Y, antiAlias, none);
260 this->drawCase2(canvas, kCol0X, kRow1Y, antiAlias, none);
261 this->drawCase3(canvas, kCol0X, kRow2Y, antiAlias, none);
262 this->drawCase4(canvas, kCol0X, kRow3Y, antiAlias, none);
263 this->drawCase5(canvas, kCol0X, kRow4Y, antiAlias, none);
bsalomon9003d1e2015-10-23 11:13:01 -0700264
Brian Salomonca769202020-05-18 16:40:59 -0400265 // Then draw a column with low filtering
Mike Reed8d29ab62021-01-23 18:10:39 -0500266 this->drawCase1(canvas, kCol1X, kRow0Y, antiAlias, low);
267 this->drawCase2(canvas, kCol1X, kRow1Y, antiAlias, low);
268 this->drawCase3(canvas, kCol1X, kRow2Y, antiAlias, low);
269 this->drawCase4(canvas, kCol1X, kRow3Y, antiAlias, low);
270 this->drawCase5(canvas, kCol1X, kRow4Y, antiAlias, low);
bsalomon9003d1e2015-10-23 11:13:01 -0700271
Brian Salomon2a7eff92020-05-19 10:22:03 -0400272 // Then draw a column with high filtering. Skip it if in kStrict mode and MIP
273 // mapping will be used. On GPU we allow bleeding at non-base levels because
274 // building a new MIP chain for the subset is expensive.
275 SkScalar scales[2];
John Stilescbe4e282020-06-01 10:38:31 -0400276 SkAssertResult(matrix.getMinMaxScales(scales));
Brian Salomon2a7eff92020-05-19 10:22:03 -0400277 if (fConstraint != SkCanvas::kStrict_SrcRectConstraint || scales[0] >= 1.f) {
Mike Reed8d29ab62021-01-23 18:10:39 -0500278 this->drawCase1(canvas, kCol2X, kRow0Y, antiAlias, high);
279 this->drawCase2(canvas, kCol2X, kRow1Y, antiAlias, high);
280 this->drawCase3(canvas, kCol2X, kRow2Y, antiAlias, high);
281 this->drawCase4(canvas, kCol2X, kRow3Y, antiAlias, high);
282 this->drawCase5(canvas, kCol2X, kRow4Y, antiAlias, high);
Brian Salomon2a7eff92020-05-19 10:22:03 -0400283 }
bsalomon9003d1e2015-10-23 11:13:01 -0700284
John Stilescbe4e282020-06-01 10:38:31 -0400285 SkPoint innerCorners[] = {{0, 0}, {0, kBottom}, {kWidth, kBottom}, {kWidth, 0}};
286 matrix.mapPoints(innerCorners, 4);
287 SkScalar x = kBlockSize + std::max({innerCorners[0].fX, innerCorners[1].fX,
288 innerCorners[2].fX, innerCorners[3].fX});
Brian Osman788b9162020-02-07 10:36:46 -0500289 maxX = std::max(maxX, x);
bsalomon9003d1e2015-10-23 11:13:01 -0700290 canvas->restore();
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000291 }
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000292 canvas->restore();
293 }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000294 }
295
bsalomon4ee6bd82015-05-27 13:23:23 -0700296 void modifyGrContextOptions(GrContextOptions* options) override {
Brian Salomon010bb462021-01-29 14:42:38 -0500297 options->fMaxTextureSizeOverride = kMaxTextureSize;
bsalomon4ee6bd82015-05-27 13:23:23 -0700298 }
bsalomon4ee6bd82015-05-27 13:23:23 -0700299
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000300private:
mtkleindbfd7ab2016-09-01 11:24:54 -0700301 static constexpr int kBlockSize = 70;
302 static constexpr int kBlockSpacing = 12;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000303
mtkleindbfd7ab2016-09-01 11:24:54 -0700304 static constexpr int kCol0X = kBlockSpacing;
305 static constexpr int kCol1X = 2*kBlockSpacing + kBlockSize;
306 static constexpr int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
Brian Salomonca769202020-05-18 16:40:59 -0400307 static constexpr int kWidth = 4*kBlockSpacing + 3*kBlockSize;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000308
mtkleindbfd7ab2016-09-01 11:24:54 -0700309 static constexpr int kRow0Y = kBlockSpacing;
310 static constexpr int kRow1Y = 2*kBlockSpacing + kBlockSize;
311 static constexpr int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
312 static constexpr int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
313 static constexpr int kRow4Y = 5*kBlockSpacing + 4*kBlockSize;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000314
mtkleindbfd7ab2016-09-01 11:24:54 -0700315 static constexpr int kSmallSize = 6;
Brian Salomon010bb462021-01-29 14:42:38 -0500316 // This must be at least as large as the GM width and height so that a surface can be made.
317 static constexpr int kMaxTextureSize = 1000;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000318
John Stilesd20a1342020-05-26 10:38:24 -0400319 SkString fShortName;
Brian Salomon6ef29332020-05-15 09:52:29 -0400320 sk_sp<SkImage> fBigImage;
321 sk_sp<SkImage> fSmallImage;
Mike Reed8d29ab62021-01-23 18:10:39 -0500322 SkRect fBigSrcRect;
323 SkRect fSmallSrcRect;
Brian Salomonca769202020-05-18 16:40:59 -0400324 SkCanvas::SrcRectConstraint fConstraint;
John Stilesd20a1342020-05-26 10:38:24 -0400325 bool fBatch = false;
John Stiles7571f9e2020-09-02 22:42:33 -0400326 using INHERITED = GM;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000327};
328
John Stilesd20a1342020-05-26 10:38:24 -0400329DEF_GM(return new SrcRectConstraintGM("strict_constraint_no_red_allowed",
330 SkCanvas::kStrict_SrcRectConstraint,
331 /*batch=*/false););
332DEF_GM(return new SrcRectConstraintGM("strict_constraint_batch_no_red_allowed",
333 SkCanvas::kStrict_SrcRectConstraint,
334 /*batch=*/true););
335DEF_GM(return new SrcRectConstraintGM("fast_constraint_red_is_allowed",
336 SkCanvas::kFast_SrcRectConstraint,
337 /*batch=*/false););
reed2adecda2016-07-25 08:11:58 -0700338
339///////////////////////////////////////////////////////////////////////////////////////////////////
reed2adecda2016-07-25 08:11:58 -0700340
reed2adecda2016-07-25 08:11:58 -0700341// Construct an image and return the inner "src" rect. Build the image such that the interior is
342// blue, with a margin of blue (2px) but then an outer margin of red.
343//
344// Show that kFast_SrcRectConstraint sees even the red margin (due to mipmapping) when the image
345// is scaled down far enough.
346//
347static sk_sp<SkImage> make_image(SkCanvas* canvas, SkRect* srcR) {
egdaniel26318c92016-07-26 08:26:46 -0700348 // Intentially making the size a power of 2 to avoid the noise from how different GPUs will
349 // produce different mipmap filtering when we have an odd sized texture.
350 const int N = 10 + 2 + 8 + 2 + 10;
reed2adecda2016-07-25 08:11:58 -0700351 SkImageInfo info = SkImageInfo::MakeN32Premul(N, N);
Mike Kleinea3f0142019-03-20 11:12:10 -0500352 auto surface = ToolUtils::makeSurface(canvas, info);
reed2adecda2016-07-25 08:11:58 -0700353 SkCanvas* c = surface->getCanvas();
354 SkRect r = SkRect::MakeIWH(info.width(), info.height());
355 SkPaint paint;
356
357 paint.setColor(SK_ColorRED);
358 c->drawRect(r, paint);
egdaniel26318c92016-07-26 08:26:46 -0700359 r.inset(10, 10);
reed2adecda2016-07-25 08:11:58 -0700360 paint.setColor(SK_ColorBLUE);
361 c->drawRect(r, paint);
362
363 *srcR = r.makeInset(2, 2);
364 return surface->makeImageSnapshot();
365}
366
367DEF_SIMPLE_GM(bleed_downscale, canvas, 360, 240) {
368 SkRect src;
369 sk_sp<SkImage> img = make_image(canvas, &src);
370 SkPaint paint;
371
372 canvas->translate(10, 10);
373
374 const SkCanvas::SrcRectConstraint constraints[] = {
375 SkCanvas::kStrict_SrcRectConstraint, SkCanvas::kFast_SrcRectConstraint
376 };
Mike Reedd396cd52021-01-23 21:14:47 -0500377 const SkSamplingOptions samplings[] = {
378 SkSamplingOptions(SkFilterMode::kNearest),
379 SkSamplingOptions(SkFilterMode::kLinear),
380 SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear),
reed2adecda2016-07-25 08:11:58 -0700381 };
382 for (auto constraint : constraints) {
383 canvas->save();
Mike Reedd396cd52021-01-23 21:14:47 -0500384 for (auto sampling : samplings) {
Mike Kleinea3f0142019-03-20 11:12:10 -0500385 auto surf = ToolUtils::makeSurface(canvas, SkImageInfo::MakeN32Premul(1, 1));
Mike Reedd396cd52021-01-23 21:14:47 -0500386 surf->getCanvas()->drawImageRect(img, src, SkRect::MakeWH(1, 1), sampling,
387 nullptr, constraint);
reed2adecda2016-07-25 08:11:58 -0700388 // now blow up the 1 pixel result
Mike Reedd396cd52021-01-23 21:14:47 -0500389 canvas->drawImageRect(surf->makeImageSnapshot(), SkRect::MakeWH(100, 100),
390 SkSamplingOptions());
reed2adecda2016-07-25 08:11:58 -0700391 canvas->translate(120, 0);
392 }
393 canvas->restore();
394 canvas->translate(0, 120);
395 }
396}
397
398