blob: 555c52911d40998ac5f3d7cd9a9f72c523d0a260 [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"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040029#include "include/gpu/GrContextOptions.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050030#include "include/private/SkTDArray.h"
31#include "src/core/SkBlurMask.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050032#include "tools/ToolUtils.h"
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000033
Brian Salomon6ef29332020-05-15 09:52:29 -040034/** Creates an image with two one-pixel wide borders around a checkerboard. The checkerboard is 2x2
35 checks where each check has as many pixels as is necessary to fill the interior. It returns
36 the image and a src rect that bounds the checkerboard portion. */
Mike Reed8d29ab62021-01-23 18:10:39 -050037std::tuple<sk_sp<SkImage>, SkRect> make_ringed_image(int width, int height) {
reeda5517e22015-07-14 10:54:12 -070038
Brian Salomon6ef29332020-05-15 09:52:29 -040039 // These are kRGBA_8888_SkColorType values.
40 static constexpr uint32_t kOuterRingColor = 0xFFFF0000,
41 kInnerRingColor = 0xFF0000FF,
42 kCheckColor1 = 0xFF000000,
43 kCheckColor2 = 0xFFFFFFFF;
44
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +000045 SkASSERT(0 == width % 2 && 0 == height % 2);
bsalomon5c1262d2015-11-09 10:06:06 -080046 SkASSERT(width >= 6 && height >= 6);
skia.committer@gmail.comed000842013-11-09 07:02:23 +000047
Brian Salomon6ef29332020-05-15 09:52:29 -040048 SkImageInfo info = SkImageInfo::Make(width, height, kRGBA_8888_SkColorType,
49 kPremul_SkAlphaType);
bsalomon5c1262d2015-11-09 10:06:06 -080050 size_t rowBytes = SkAlign4(info.minRowBytes());
Brian Salomon6ef29332020-05-15 09:52:29 -040051 SkBitmap bitmap;
52 bitmap.allocPixels(info, rowBytes);
bsalomon5c1262d2015-11-09 10:06:06 -080053
Brian Salomon6ef29332020-05-15 09:52:29 -040054 uint32_t* scanline = bitmap.getAddr32(0, 0);
bsalomon5c1262d2015-11-09 10:06:06 -080055 for (int x = 0; x < width; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -040056 scanline[x] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080057 }
Brian Salomon6ef29332020-05-15 09:52:29 -040058 scanline = bitmap.getAddr32(0, 1);
59 scanline[0] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080060 for (int x = 1; x < width - 1; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -040061 scanline[x] = kInnerRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080062 }
Brian Salomon6ef29332020-05-15 09:52:29 -040063 scanline[width - 1] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080064
65 for (int y = 2; y < height / 2; ++y) {
Brian Salomon6ef29332020-05-15 09:52:29 -040066 scanline = bitmap.getAddr32(0, y);
67 scanline[0] = kOuterRingColor;
68 scanline[1] = kInnerRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080069 for (int x = 2; x < width / 2; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -040070 scanline[x] = kCheckColor1;
bsalomon5c1262d2015-11-09 10:06:06 -080071 }
72 for (int x = width / 2; x < width - 2; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -040073 scanline[x] = kCheckColor2;
bsalomon5c1262d2015-11-09 10:06:06 -080074 }
Brian Salomon6ef29332020-05-15 09:52:29 -040075 scanline[width - 2] = kInnerRingColor;
76 scanline[width - 1] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080077 }
78
79 for (int y = height / 2; y < height - 2; ++y) {
Brian Salomon6ef29332020-05-15 09:52:29 -040080 scanline = bitmap.getAddr32(0, y);
81 scanline[0] = kOuterRingColor;
82 scanline[1] = kInnerRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080083 for (int x = 2; x < width / 2; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -040084 scanline[x] = kCheckColor2;
bsalomon5c1262d2015-11-09 10:06:06 -080085 }
86 for (int x = width / 2; x < width - 2; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -040087 scanline[x] = kCheckColor1;
bsalomon5c1262d2015-11-09 10:06:06 -080088 }
Brian Salomon6ef29332020-05-15 09:52:29 -040089 scanline[width - 2] = kInnerRingColor;
90 scanline[width - 1] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080091 }
92
Brian Salomon6ef29332020-05-15 09:52:29 -040093 scanline = bitmap.getAddr32(0, height - 2);
94 scanline[0] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080095 for (int x = 1; x < width - 1; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -040096 scanline[x] = kInnerRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080097 }
Brian Salomon6ef29332020-05-15 09:52:29 -040098 scanline[width - 1] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080099
Brian Salomon6ef29332020-05-15 09:52:29 -0400100 scanline = bitmap.getAddr32(0, height - 1);
bsalomon5c1262d2015-11-09 10:06:06 -0800101 for (int x = 0; x < width; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -0400102 scanline[x] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -0800103 }
Brian Salomon6ef29332020-05-15 09:52:29 -0400104 bitmap.setImmutable();
Mike Reed8d29ab62021-01-23 18:10:39 -0500105 return {bitmap.asImage(), SkRect::Make({2, 2, width - 2, height - 2})};
bsalomon5c1262d2015-11-09 10:06:06 -0800106}
107
Brian Salomon6ef29332020-05-15 09:52:29 -0400108/**
Brian Salomonca769202020-05-18 16:40:59 -0400109 * These GMs exercise the behavior of the drawImageRect and its SrcRectConstraint parameter. They
110 * tests various matrices, filter qualities, and interaction with mask filters. They also exercise
Brian Salomon6ef29332020-05-15 09:52:29 -0400111 * the tiling image draws of SkGpuDevice by overriding the maximum texture size of the GrContext.
112 */
Brian Salomonca769202020-05-18 16:40:59 -0400113class SrcRectConstraintGM : public skiagm::GM {
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000114public:
John Stilesd20a1342020-05-26 10:38:24 -0400115 SrcRectConstraintGM(const char* shortName, SkCanvas::SrcRectConstraint constraint, bool batch)
116 : fShortName(shortName)
117 , fConstraint(constraint)
Brian Salomon010bb462021-01-29 14:42:38 -0500118 , fBatch(batch) {
119 // Make sure GPU SkSurfaces can be created for this GM.
120 SkASSERT(this->onISize().width() <= kMaxTextureSize &&
121 this->onISize().height() <= kMaxTextureSize);
122 }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000123
124protected:
John Stilesd20a1342020-05-26 10:38:24 -0400125 SkString onShortName() override { return fShortName; }
Brian Salomonca769202020-05-18 16:40:59 -0400126 SkISize onISize() override { return SkISize::Make(800, 1000); }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000127
Mike Reed8d29ab62021-01-23 18:10:39 -0500128 void drawImage(SkCanvas* canvas, sk_sp<SkImage> image, SkRect srcRect, SkRect dstRect,
129 const SkSamplingOptions& sampling, SkPaint* paint) {
John Stilesd20a1342020-05-26 10:38:24 -0400130 if (fBatch) {
131 SkCanvas::ImageSetEntry imageSetEntry[1];
132 imageSetEntry[0].fImage = image;
Mike Reed8d29ab62021-01-23 18:10:39 -0500133 imageSetEntry[0].fSrcRect = srcRect;
John Stilesd20a1342020-05-26 10:38:24 -0400134 imageSetEntry[0].fDstRect = dstRect;
135 imageSetEntry[0].fAAFlags = paint->isAntiAlias() ? SkCanvas::kAll_QuadAAFlags
136 : SkCanvas::kNone_QuadAAFlags;
137 canvas->experimental_DrawEdgeAAImageSet(imageSetEntry, SK_ARRAY_COUNT(imageSetEntry),
138 /*dstClips=*/nullptr,
139 /*preViewMatrices=*/nullptr,
Mike Reed8d29ab62021-01-23 18:10:39 -0500140 sampling, paint, fConstraint);
John Stilesd20a1342020-05-26 10:38:24 -0400141 } else {
Mike Reed8d29ab62021-01-23 18:10:39 -0500142 canvas->drawImageRect(image.get(), srcRect, dstRect, sampling, paint, fConstraint);
John Stilesd20a1342020-05-26 10:38:24 -0400143 }
144 }
145
bsalomon5c1262d2015-11-09 10:06:06 -0800146 // Draw the area of interest of the small image
Mike Reed8d29ab62021-01-23 18:10:39 -0500147 void drawCase1(SkCanvas* canvas, int transX, int transY, bool aa,
148 const SkSamplingOptions& sampling) {
reeda5517e22015-07-14 10:54:12 -0700149 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
150 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000151
152 SkPaint paint;
bsalomon9003d1e2015-10-23 11:13:01 -0700153 paint.setColor(SK_ColorBLUE);
154 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000155
Mike Reed8d29ab62021-01-23 18:10:39 -0500156 drawImage(canvas, fSmallImage, fSmallSrcRect, dst, sampling, &paint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000157 }
158
bsalomon5c1262d2015-11-09 10:06:06 -0800159 // Draw the area of interest of the large image
Mike Reed8d29ab62021-01-23 18:10:39 -0500160 void drawCase2(SkCanvas* canvas, int transX, int transY, bool aa,
161 const SkSamplingOptions& sampling) {
reeda5517e22015-07-14 10:54:12 -0700162 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
163 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000164
165 SkPaint paint;
bsalomon9003d1e2015-10-23 11:13:01 -0700166 paint.setColor(SK_ColorBLUE);
167 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000168
Mike Reed8d29ab62021-01-23 18:10:39 -0500169 drawImage(canvas, fBigImage, fBigSrcRect, dst, sampling, &paint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000170 }
171
bsalomon5c1262d2015-11-09 10:06:06 -0800172 // Draw upper-left 1/4 of the area of interest of the large image
Mike Reed8d29ab62021-01-23 18:10:39 -0500173 void drawCase3(SkCanvas* canvas, int transX, int transY, bool aa,
174 const SkSamplingOptions& sampling) {
175 SkRect src = SkRect::MakeXYWH(fBigSrcRect.fLeft,
176 fBigSrcRect.fTop,
177 fBigSrcRect.width()/2,
178 fBigSrcRect.height()/2);
reeda5517e22015-07-14 10:54:12 -0700179 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
180 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000181
182 SkPaint paint;
bsalomon9003d1e2015-10-23 11:13:01 -0700183 paint.setColor(SK_ColorBLUE);
184 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000185
Mike Reed8d29ab62021-01-23 18:10:39 -0500186 drawImage(canvas, fBigImage, src, dst, sampling, &paint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000187 }
188
bsalomon5c1262d2015-11-09 10:06:06 -0800189 // Draw the area of interest of the small image with a normal blur
Mike Reed8d29ab62021-01-23 18:10:39 -0500190 void drawCase4(SkCanvas* canvas, int transX, int transY, bool aa,
191 const SkSamplingOptions& sampling) {
reeda5517e22015-07-14 10:54:12 -0700192 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
193 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000194
195 SkPaint paint;
Mike Reed1be1f8d2018-03-14 13:01:17 -0400196 paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle,
reedefdfd512016-04-04 10:02:58 -0700197 SkBlurMask::ConvertRadiusToSigma(3)));
bsalomon9003d1e2015-10-23 11:13:01 -0700198 paint.setColor(SK_ColorBLUE);
199 paint.setAntiAlias(aa);
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000200
Mike Reed8d29ab62021-01-23 18:10:39 -0500201 drawImage(canvas, fSmallImage, fSmallSrcRect, dst, sampling, &paint);
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000202 }
203
bsalomon5c1262d2015-11-09 10:06:06 -0800204 // Draw the area of interest of the small image with a outer blur
Mike Reed8d29ab62021-01-23 18:10:39 -0500205 void drawCase5(SkCanvas* canvas, int transX, int transY, bool aa,
206 const SkSamplingOptions& sampling) {
bsalomonf57ef1c2015-11-04 04:36:12 -0800207 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
208 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
209
210 SkPaint paint;
Mike Reed1be1f8d2018-03-14 13:01:17 -0400211 paint.setMaskFilter(SkMaskFilter::MakeBlur(kOuter_SkBlurStyle,
reedefdfd512016-04-04 10:02:58 -0700212 SkBlurMask::ConvertRadiusToSigma(7)));
bsalomonf57ef1c2015-11-04 04:36:12 -0800213 paint.setColor(SK_ColorBLUE);
214 paint.setAntiAlias(aa);
215
Mike Reed8d29ab62021-01-23 18:10:39 -0500216 drawImage(canvas, fSmallImage, fSmallSrcRect, dst, sampling, &paint);
bsalomonf57ef1c2015-11-04 04:36:12 -0800217 }
218
bsalomona2e08372016-07-13 14:50:17 -0700219 void onOnceBeforeDraw() override {
Brian Salomon010bb462021-01-29 14:42:38 -0500220 std::tie(fBigImage, fBigSrcRect) = make_ringed_image(2*kMaxTextureSize, 2*kMaxTextureSize);
Brian Salomon6ef29332020-05-15 09:52:29 -0400221 std::tie(fSmallImage, fSmallSrcRect) = make_ringed_image(kSmallSize, kSmallSize);
bsalomona2e08372016-07-13 14:50:17 -0700222 }
223
mtklein36352bf2015-03-25 18:17:31 -0700224 void onDraw(SkCanvas* canvas) override {
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000225 canvas->clear(SK_ColorGRAY);
John Stilescbe4e282020-06-01 10:38:31 -0400226 std::vector<SkMatrix> matrices;
bsalomon9003d1e2015-10-23 11:13:01 -0700227 // Draw with identity
John Stilescbe4e282020-06-01 10:38:31 -0400228 matrices.push_back(SkMatrix::I());
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000229
bsalomon9003d1e2015-10-23 11:13:01 -0700230 // Draw with rotation and scale down in x, up in y.
231 SkMatrix m;
mtkleindbfd7ab2016-09-01 11:24:54 -0700232 constexpr SkScalar kBottom = SkIntToScalar(kRow4Y + kBlockSize + kBlockSpacing);
bsalomon9003d1e2015-10-23 11:13:01 -0700233 m.setTranslate(0, kBottom);
234 m.preRotate(15.f, 0, kBottom + kBlockSpacing);
235 m.preScale(0.71f, 1.22f);
John Stilescbe4e282020-06-01 10:38:31 -0400236 matrices.push_back(m);
bsalomon9003d1e2015-10-23 11:13:01 -0700237
238 // 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 -0400239 SkPoint corners[] = {{0, 0}, {0, kBottom}, {kWidth, kBottom}, {kWidth, 0}};
240 matrices.back().mapPoints(corners, 4);
bsalomon9003d1e2015-10-23 11:13:01 -0700241 SkScalar y = (corners[0].fY + corners[1].fY + corners[2].fY + corners[3].fY) / 4;
John Stilescbe4e282020-06-01 10:38:31 -0400242 SkScalar x = std::max({corners[0].fX, corners[1].fX, corners[2].fX, corners[3].fX});
bsalomon9003d1e2015-10-23 11:13:01 -0700243 m.setTranslate(x, y);
244 m.preScale(0.2f, 0.2f);
John Stilescbe4e282020-06-01 10:38:31 -0400245 matrices.push_back(m);
bsalomon9003d1e2015-10-23 11:13:01 -0700246
Mike Reed8d29ab62021-01-23 18:10:39 -0500247 const SkSamplingOptions none(SkFilterMode::kNearest);
248 const SkSamplingOptions low(SkFilterMode::kLinear);
Mike Reedf3ac2af2021-02-05 12:55:38 -0500249 const SkSamplingOptions high(SkCubicResampler::Mitchell());
Mike Reed8d29ab62021-01-23 18:10:39 -0500250
bsalomon9003d1e2015-10-23 11:13:01 -0700251 SkScalar maxX = 0;
John Stilescbe4e282020-06-01 10:38:31 -0400252 for (bool antiAlias : {false, true}) {
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000253 canvas->save();
bsalomon9003d1e2015-10-23 11:13:01 -0700254 canvas->translate(maxX, 0);
John Stilescbe4e282020-06-01 10:38:31 -0400255 for (const SkMatrix& matrix : matrices) {
bsalomon9003d1e2015-10-23 11:13:01 -0700256 canvas->save();
John Stilescbe4e282020-06-01 10:38:31 -0400257 canvas->concat(matrix);
bsalomon9003d1e2015-10-23 11:13:01 -0700258
Brian Salomonca769202020-05-18 16:40:59 -0400259 // First draw a column with no filtering
Mike Reed8d29ab62021-01-23 18:10:39 -0500260 this->drawCase1(canvas, kCol0X, kRow0Y, antiAlias, none);
261 this->drawCase2(canvas, kCol0X, kRow1Y, antiAlias, none);
262 this->drawCase3(canvas, kCol0X, kRow2Y, antiAlias, none);
263 this->drawCase4(canvas, kCol0X, kRow3Y, antiAlias, none);
264 this->drawCase5(canvas, kCol0X, kRow4Y, antiAlias, none);
bsalomon9003d1e2015-10-23 11:13:01 -0700265
Brian Salomonca769202020-05-18 16:40:59 -0400266 // Then draw a column with low filtering
Mike Reed8d29ab62021-01-23 18:10:39 -0500267 this->drawCase1(canvas, kCol1X, kRow0Y, antiAlias, low);
268 this->drawCase2(canvas, kCol1X, kRow1Y, antiAlias, low);
269 this->drawCase3(canvas, kCol1X, kRow2Y, antiAlias, low);
270 this->drawCase4(canvas, kCol1X, kRow3Y, antiAlias, low);
271 this->drawCase5(canvas, kCol1X, kRow4Y, antiAlias, low);
bsalomon9003d1e2015-10-23 11:13:01 -0700272
Brian Salomon2a7eff92020-05-19 10:22:03 -0400273 // Then draw a column with high filtering. Skip it if in kStrict mode and MIP
274 // mapping will be used. On GPU we allow bleeding at non-base levels because
275 // building a new MIP chain for the subset is expensive.
276 SkScalar scales[2];
John Stilescbe4e282020-06-01 10:38:31 -0400277 SkAssertResult(matrix.getMinMaxScales(scales));
Brian Salomon2a7eff92020-05-19 10:22:03 -0400278 if (fConstraint != SkCanvas::kStrict_SrcRectConstraint || scales[0] >= 1.f) {
Mike Reed8d29ab62021-01-23 18:10:39 -0500279 this->drawCase1(canvas, kCol2X, kRow0Y, antiAlias, high);
280 this->drawCase2(canvas, kCol2X, kRow1Y, antiAlias, high);
281 this->drawCase3(canvas, kCol2X, kRow2Y, antiAlias, high);
282 this->drawCase4(canvas, kCol2X, kRow3Y, antiAlias, high);
283 this->drawCase5(canvas, kCol2X, kRow4Y, antiAlias, high);
Brian Salomon2a7eff92020-05-19 10:22:03 -0400284 }
bsalomon9003d1e2015-10-23 11:13:01 -0700285
John Stilescbe4e282020-06-01 10:38:31 -0400286 SkPoint innerCorners[] = {{0, 0}, {0, kBottom}, {kWidth, kBottom}, {kWidth, 0}};
287 matrix.mapPoints(innerCorners, 4);
288 SkScalar x = kBlockSize + std::max({innerCorners[0].fX, innerCorners[1].fX,
289 innerCorners[2].fX, innerCorners[3].fX});
Brian Osman788b9162020-02-07 10:36:46 -0500290 maxX = std::max(maxX, x);
bsalomon9003d1e2015-10-23 11:13:01 -0700291 canvas->restore();
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000292 }
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000293 canvas->restore();
294 }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000295 }
296
bsalomon4ee6bd82015-05-27 13:23:23 -0700297 void modifyGrContextOptions(GrContextOptions* options) override {
Brian Salomon010bb462021-01-29 14:42:38 -0500298 options->fMaxTextureSizeOverride = kMaxTextureSize;
bsalomon4ee6bd82015-05-27 13:23:23 -0700299 }
bsalomon4ee6bd82015-05-27 13:23:23 -0700300
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000301private:
mtkleindbfd7ab2016-09-01 11:24:54 -0700302 static constexpr int kBlockSize = 70;
303 static constexpr int kBlockSpacing = 12;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000304
mtkleindbfd7ab2016-09-01 11:24:54 -0700305 static constexpr int kCol0X = kBlockSpacing;
306 static constexpr int kCol1X = 2*kBlockSpacing + kBlockSize;
307 static constexpr int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
Brian Salomonca769202020-05-18 16:40:59 -0400308 static constexpr int kWidth = 4*kBlockSpacing + 3*kBlockSize;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000309
mtkleindbfd7ab2016-09-01 11:24:54 -0700310 static constexpr int kRow0Y = kBlockSpacing;
311 static constexpr int kRow1Y = 2*kBlockSpacing + kBlockSize;
312 static constexpr int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
313 static constexpr int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
314 static constexpr int kRow4Y = 5*kBlockSpacing + 4*kBlockSize;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000315
mtkleindbfd7ab2016-09-01 11:24:54 -0700316 static constexpr int kSmallSize = 6;
Brian Salomon010bb462021-01-29 14:42:38 -0500317 // This must be at least as large as the GM width and height so that a surface can be made.
318 static constexpr int kMaxTextureSize = 1000;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000319
John Stilesd20a1342020-05-26 10:38:24 -0400320 SkString fShortName;
Brian Salomon6ef29332020-05-15 09:52:29 -0400321 sk_sp<SkImage> fBigImage;
322 sk_sp<SkImage> fSmallImage;
Mike Reed8d29ab62021-01-23 18:10:39 -0500323 SkRect fBigSrcRect;
324 SkRect fSmallSrcRect;
Brian Salomonca769202020-05-18 16:40:59 -0400325 SkCanvas::SrcRectConstraint fConstraint;
John Stilesd20a1342020-05-26 10:38:24 -0400326 bool fBatch = false;
John Stiles7571f9e2020-09-02 22:42:33 -0400327 using INHERITED = GM;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000328};
329
John Stilesd20a1342020-05-26 10:38:24 -0400330DEF_GM(return new SrcRectConstraintGM("strict_constraint_no_red_allowed",
331 SkCanvas::kStrict_SrcRectConstraint,
332 /*batch=*/false););
333DEF_GM(return new SrcRectConstraintGM("strict_constraint_batch_no_red_allowed",
334 SkCanvas::kStrict_SrcRectConstraint,
335 /*batch=*/true););
336DEF_GM(return new SrcRectConstraintGM("fast_constraint_red_is_allowed",
337 SkCanvas::kFast_SrcRectConstraint,
338 /*batch=*/false););
reed2adecda2016-07-25 08:11:58 -0700339
340///////////////////////////////////////////////////////////////////////////////////////////////////
reed2adecda2016-07-25 08:11:58 -0700341
reed2adecda2016-07-25 08:11:58 -0700342// Construct an image and return the inner "src" rect. Build the image such that the interior is
343// blue, with a margin of blue (2px) but then an outer margin of red.
344//
345// Show that kFast_SrcRectConstraint sees even the red margin (due to mipmapping) when the image
346// is scaled down far enough.
347//
348static sk_sp<SkImage> make_image(SkCanvas* canvas, SkRect* srcR) {
egdaniel26318c92016-07-26 08:26:46 -0700349 // Intentially making the size a power of 2 to avoid the noise from how different GPUs will
350 // produce different mipmap filtering when we have an odd sized texture.
351 const int N = 10 + 2 + 8 + 2 + 10;
reed2adecda2016-07-25 08:11:58 -0700352 SkImageInfo info = SkImageInfo::MakeN32Premul(N, N);
Mike Kleinea3f0142019-03-20 11:12:10 -0500353 auto surface = ToolUtils::makeSurface(canvas, info);
reed2adecda2016-07-25 08:11:58 -0700354 SkCanvas* c = surface->getCanvas();
355 SkRect r = SkRect::MakeIWH(info.width(), info.height());
356 SkPaint paint;
357
358 paint.setColor(SK_ColorRED);
359 c->drawRect(r, paint);
egdaniel26318c92016-07-26 08:26:46 -0700360 r.inset(10, 10);
reed2adecda2016-07-25 08:11:58 -0700361 paint.setColor(SK_ColorBLUE);
362 c->drawRect(r, paint);
363
364 *srcR = r.makeInset(2, 2);
365 return surface->makeImageSnapshot();
366}
367
368DEF_SIMPLE_GM(bleed_downscale, canvas, 360, 240) {
369 SkRect src;
370 sk_sp<SkImage> img = make_image(canvas, &src);
371 SkPaint paint;
372
373 canvas->translate(10, 10);
374
375 const SkCanvas::SrcRectConstraint constraints[] = {
376 SkCanvas::kStrict_SrcRectConstraint, SkCanvas::kFast_SrcRectConstraint
377 };
Mike Reedd396cd52021-01-23 21:14:47 -0500378 const SkSamplingOptions samplings[] = {
379 SkSamplingOptions(SkFilterMode::kNearest),
380 SkSamplingOptions(SkFilterMode::kLinear),
381 SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear),
reed2adecda2016-07-25 08:11:58 -0700382 };
383 for (auto constraint : constraints) {
384 canvas->save();
Mike Reedd396cd52021-01-23 21:14:47 -0500385 for (auto sampling : samplings) {
Mike Kleinea3f0142019-03-20 11:12:10 -0500386 auto surf = ToolUtils::makeSurface(canvas, SkImageInfo::MakeN32Premul(1, 1));
Mike Reedd396cd52021-01-23 21:14:47 -0500387 surf->getCanvas()->drawImageRect(img, src, SkRect::MakeWH(1, 1), sampling,
388 nullptr, constraint);
reed2adecda2016-07-25 08:11:58 -0700389 // now blow up the 1 pixel result
Mike Reedd396cd52021-01-23 21:14:47 -0500390 canvas->drawImageRect(surf->makeImageSnapshot(), SkRect::MakeWH(100, 100),
391 SkSamplingOptions());
reed2adecda2016-07-25 08:11:58 -0700392 canvas->translate(120, 0);
393 }
394 canvas->restore();
395 canvas->translate(0, 120);
396 }
397}
398
399