blob: 1c0d6e035237b5935469ebcd709b8fcfcf13dd86 [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);
John Stilesacf71642021-08-12 22:33:57 -0400240 m.setTranslate(std::max({corners[0].fX, corners[1].fX, corners[2].fX, corners[3].fX}),
241 (corners[0].fY + corners[1].fY + corners[2].fY + corners[3].fY) / 4);
bsalomon9003d1e2015-10-23 11:13:01 -0700242 m.preScale(0.2f, 0.2f);
John Stilescbe4e282020-06-01 10:38:31 -0400243 matrices.push_back(m);
bsalomon9003d1e2015-10-23 11:13:01 -0700244
Mike Reed8d29ab62021-01-23 18:10:39 -0500245 const SkSamplingOptions none(SkFilterMode::kNearest);
246 const SkSamplingOptions low(SkFilterMode::kLinear);
Mike Reedf3ac2af2021-02-05 12:55:38 -0500247 const SkSamplingOptions high(SkCubicResampler::Mitchell());
Mike Reed8d29ab62021-01-23 18:10:39 -0500248
bsalomon9003d1e2015-10-23 11:13:01 -0700249 SkScalar maxX = 0;
John Stilescbe4e282020-06-01 10:38:31 -0400250 for (bool antiAlias : {false, true}) {
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000251 canvas->save();
bsalomon9003d1e2015-10-23 11:13:01 -0700252 canvas->translate(maxX, 0);
John Stilescbe4e282020-06-01 10:38:31 -0400253 for (const SkMatrix& matrix : matrices) {
bsalomon9003d1e2015-10-23 11:13:01 -0700254 canvas->save();
John Stilescbe4e282020-06-01 10:38:31 -0400255 canvas->concat(matrix);
bsalomon9003d1e2015-10-23 11:13:01 -0700256
Brian Salomonca769202020-05-18 16:40:59 -0400257 // First draw a column with no filtering
Mike Reed8d29ab62021-01-23 18:10:39 -0500258 this->drawCase1(canvas, kCol0X, kRow0Y, antiAlias, none);
259 this->drawCase2(canvas, kCol0X, kRow1Y, antiAlias, none);
260 this->drawCase3(canvas, kCol0X, kRow2Y, antiAlias, none);
261 this->drawCase4(canvas, kCol0X, kRow3Y, antiAlias, none);
262 this->drawCase5(canvas, kCol0X, kRow4Y, antiAlias, none);
bsalomon9003d1e2015-10-23 11:13:01 -0700263
Brian Salomonca769202020-05-18 16:40:59 -0400264 // Then draw a column with low filtering
Mike Reed8d29ab62021-01-23 18:10:39 -0500265 this->drawCase1(canvas, kCol1X, kRow0Y, antiAlias, low);
266 this->drawCase2(canvas, kCol1X, kRow1Y, antiAlias, low);
267 this->drawCase3(canvas, kCol1X, kRow2Y, antiAlias, low);
268 this->drawCase4(canvas, kCol1X, kRow3Y, antiAlias, low);
269 this->drawCase5(canvas, kCol1X, kRow4Y, antiAlias, low);
bsalomon9003d1e2015-10-23 11:13:01 -0700270
Brian Salomon2a7eff92020-05-19 10:22:03 -0400271 // Then draw a column with high filtering. Skip it if in kStrict mode and MIP
272 // mapping will be used. On GPU we allow bleeding at non-base levels because
273 // building a new MIP chain for the subset is expensive.
274 SkScalar scales[2];
John Stilescbe4e282020-06-01 10:38:31 -0400275 SkAssertResult(matrix.getMinMaxScales(scales));
Brian Salomon2a7eff92020-05-19 10:22:03 -0400276 if (fConstraint != SkCanvas::kStrict_SrcRectConstraint || scales[0] >= 1.f) {
Mike Reed8d29ab62021-01-23 18:10:39 -0500277 this->drawCase1(canvas, kCol2X, kRow0Y, antiAlias, high);
278 this->drawCase2(canvas, kCol2X, kRow1Y, antiAlias, high);
279 this->drawCase3(canvas, kCol2X, kRow2Y, antiAlias, high);
280 this->drawCase4(canvas, kCol2X, kRow3Y, antiAlias, high);
281 this->drawCase5(canvas, kCol2X, kRow4Y, antiAlias, high);
Brian Salomon2a7eff92020-05-19 10:22:03 -0400282 }
bsalomon9003d1e2015-10-23 11:13:01 -0700283
John Stilescbe4e282020-06-01 10:38:31 -0400284 SkPoint innerCorners[] = {{0, 0}, {0, kBottom}, {kWidth, kBottom}, {kWidth, 0}};
285 matrix.mapPoints(innerCorners, 4);
286 SkScalar x = kBlockSize + std::max({innerCorners[0].fX, innerCorners[1].fX,
287 innerCorners[2].fX, innerCorners[3].fX});
Brian Osman788b9162020-02-07 10:36:46 -0500288 maxX = std::max(maxX, x);
bsalomon9003d1e2015-10-23 11:13:01 -0700289 canvas->restore();
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000290 }
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000291 canvas->restore();
292 }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000293 }
294
bsalomon4ee6bd82015-05-27 13:23:23 -0700295 void modifyGrContextOptions(GrContextOptions* options) override {
Brian Salomon010bb462021-01-29 14:42:38 -0500296 options->fMaxTextureSizeOverride = kMaxTextureSize;
bsalomon4ee6bd82015-05-27 13:23:23 -0700297 }
bsalomon4ee6bd82015-05-27 13:23:23 -0700298
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000299private:
mtkleindbfd7ab2016-09-01 11:24:54 -0700300 static constexpr int kBlockSize = 70;
301 static constexpr int kBlockSpacing = 12;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000302
mtkleindbfd7ab2016-09-01 11:24:54 -0700303 static constexpr int kCol0X = kBlockSpacing;
304 static constexpr int kCol1X = 2*kBlockSpacing + kBlockSize;
305 static constexpr int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
Brian Salomonca769202020-05-18 16:40:59 -0400306 static constexpr int kWidth = 4*kBlockSpacing + 3*kBlockSize;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000307
mtkleindbfd7ab2016-09-01 11:24:54 -0700308 static constexpr int kRow0Y = kBlockSpacing;
309 static constexpr int kRow1Y = 2*kBlockSpacing + kBlockSize;
310 static constexpr int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
311 static constexpr int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
312 static constexpr int kRow4Y = 5*kBlockSpacing + 4*kBlockSize;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000313
mtkleindbfd7ab2016-09-01 11:24:54 -0700314 static constexpr int kSmallSize = 6;
Brian Salomon010bb462021-01-29 14:42:38 -0500315 // This must be at least as large as the GM width and height so that a surface can be made.
316 static constexpr int kMaxTextureSize = 1000;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000317
John Stilesd20a1342020-05-26 10:38:24 -0400318 SkString fShortName;
Brian Salomon6ef29332020-05-15 09:52:29 -0400319 sk_sp<SkImage> fBigImage;
320 sk_sp<SkImage> fSmallImage;
Mike Reed8d29ab62021-01-23 18:10:39 -0500321 SkRect fBigSrcRect;
322 SkRect fSmallSrcRect;
Brian Salomonca769202020-05-18 16:40:59 -0400323 SkCanvas::SrcRectConstraint fConstraint;
John Stilesd20a1342020-05-26 10:38:24 -0400324 bool fBatch = false;
John Stiles7571f9e2020-09-02 22:42:33 -0400325 using INHERITED = GM;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000326};
327
John Stilesd20a1342020-05-26 10:38:24 -0400328DEF_GM(return new SrcRectConstraintGM("strict_constraint_no_red_allowed",
329 SkCanvas::kStrict_SrcRectConstraint,
330 /*batch=*/false););
331DEF_GM(return new SrcRectConstraintGM("strict_constraint_batch_no_red_allowed",
332 SkCanvas::kStrict_SrcRectConstraint,
333 /*batch=*/true););
334DEF_GM(return new SrcRectConstraintGM("fast_constraint_red_is_allowed",
335 SkCanvas::kFast_SrcRectConstraint,
336 /*batch=*/false););
reed2adecda2016-07-25 08:11:58 -0700337
338///////////////////////////////////////////////////////////////////////////////////////////////////
reed2adecda2016-07-25 08:11:58 -0700339
reed2adecda2016-07-25 08:11:58 -0700340// Construct an image and return the inner "src" rect. Build the image such that the interior is
341// blue, with a margin of blue (2px) but then an outer margin of red.
342//
343// Show that kFast_SrcRectConstraint sees even the red margin (due to mipmapping) when the image
344// is scaled down far enough.
345//
346static sk_sp<SkImage> make_image(SkCanvas* canvas, SkRect* srcR) {
egdaniel26318c92016-07-26 08:26:46 -0700347 // Intentially making the size a power of 2 to avoid the noise from how different GPUs will
348 // produce different mipmap filtering when we have an odd sized texture.
349 const int N = 10 + 2 + 8 + 2 + 10;
reed2adecda2016-07-25 08:11:58 -0700350 SkImageInfo info = SkImageInfo::MakeN32Premul(N, N);
Mike Kleinea3f0142019-03-20 11:12:10 -0500351 auto surface = ToolUtils::makeSurface(canvas, info);
reed2adecda2016-07-25 08:11:58 -0700352 SkCanvas* c = surface->getCanvas();
353 SkRect r = SkRect::MakeIWH(info.width(), info.height());
354 SkPaint paint;
355
356 paint.setColor(SK_ColorRED);
357 c->drawRect(r, paint);
egdaniel26318c92016-07-26 08:26:46 -0700358 r.inset(10, 10);
reed2adecda2016-07-25 08:11:58 -0700359 paint.setColor(SK_ColorBLUE);
360 c->drawRect(r, paint);
361
362 *srcR = r.makeInset(2, 2);
363 return surface->makeImageSnapshot();
364}
365
366DEF_SIMPLE_GM(bleed_downscale, canvas, 360, 240) {
367 SkRect src;
368 sk_sp<SkImage> img = make_image(canvas, &src);
369 SkPaint paint;
370
371 canvas->translate(10, 10);
372
373 const SkCanvas::SrcRectConstraint constraints[] = {
374 SkCanvas::kStrict_SrcRectConstraint, SkCanvas::kFast_SrcRectConstraint
375 };
Mike Reedd396cd52021-01-23 21:14:47 -0500376 const SkSamplingOptions samplings[] = {
377 SkSamplingOptions(SkFilterMode::kNearest),
378 SkSamplingOptions(SkFilterMode::kLinear),
379 SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear),
reed2adecda2016-07-25 08:11:58 -0700380 };
381 for (auto constraint : constraints) {
382 canvas->save();
Mike Reedd396cd52021-01-23 21:14:47 -0500383 for (auto sampling : samplings) {
Mike Kleinea3f0142019-03-20 11:12:10 -0500384 auto surf = ToolUtils::makeSurface(canvas, SkImageInfo::MakeN32Premul(1, 1));
Mike Reedd396cd52021-01-23 21:14:47 -0500385 surf->getCanvas()->drawImageRect(img, src, SkRect::MakeWH(1, 1), sampling,
386 nullptr, constraint);
reed2adecda2016-07-25 08:11:58 -0700387 // now blow up the 1 pixel result
Mike Reedd396cd52021-01-23 21:14:47 -0500388 canvas->drawImageRect(surf->makeImageSnapshot(), SkRect::MakeWH(100, 100),
389 SkSamplingOptions());
reed2adecda2016-07-25 08:11:58 -0700390 canvas->translate(120, 0);
391 }
392 canvas->restore();
393 canvas->translate(0, 120);
394 }
395}
396
397