blob: 12682c1023dd2b0413c511cd0a271316856736a1 [file] [log] [blame]
robertphillips@google.comaaa9b292013-07-25 21:34:00 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "gm.h"
robertphillips@google.comb7061172013-09-06 14:16:12 +00009#include "SkBlurMask.h"
robertphillips@google.com2cc0b472013-08-20 16:51:20 +000010#include "SkBlurMaskFilter.h"
robertphillips@google.comb7061172013-09-06 14:16:12 +000011#include "SkCanvas.h"
reeda5517e22015-07-14 10:54:12 -070012#include "SkImage.h"
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000013
14#if SK_SUPPORT_GPU
15#include "GrContext.h"
bsalomon4ee6bd82015-05-27 13:23:23 -070016#include "GrContextOptions.h"
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000017#endif
18
reeda5517e22015-07-14 10:54:12 -070019static void draw_bitmap_rect(SkCanvas* canvas, const SkBitmap& bitmap, const SkImage*,
reede47829b2015-08-06 10:02:53 -070020 const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -070021 const SkPaint* paint, SkCanvas::SrcRectConstraint constraint) {
22 canvas->drawBitmapRect(bitmap, src, dst, paint, constraint);
23}
24
25static void draw_image_rect(SkCanvas* canvas, const SkBitmap&, const SkImage* image,
reede47829b2015-08-06 10:02:53 -070026 const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -070027 const SkPaint* paint, SkCanvas::SrcRectConstraint constraint) {
28 canvas->drawImageRect(image, src, dst, paint, constraint);
29}
30
31enum BleedTest {
32 kUseBitmap_BleedTest,
33 kUseImage_BleedTest,
34};
35
36const struct {
37 const char* fName;
reede47829b2015-08-06 10:02:53 -070038 void (*fDraw)(SkCanvas*, const SkBitmap&, const SkImage*, const SkRect&, const SkRect&,
reeda5517e22015-07-14 10:54:12 -070039 const SkPaint*, SkCanvas::SrcRectConstraint);
40} gBleedRec[] = {
41 { "bleed", draw_bitmap_rect },
42 { "bleed_image", draw_image_rect },
43};
44
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +000045// Create a black&white checked texture with 2 1-pixel rings
46// around the outside edge. The inner ring is red and the outer ring is blue.
47static void make_ringed_bitmap(SkBitmap* result, int width, int height) {
48 SkASSERT(0 == width % 2 && 0 == height % 2);
skia.committer@gmail.comed000842013-11-09 07:02:23 +000049
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +000050 static const SkPMColor kRed = SkPreMultiplyColor(SK_ColorRED);
51 static const SkPMColor kBlue = SkPreMultiplyColor(SK_ColorBLUE);
52 static const SkPMColor kBlack = SkPreMultiplyColor(SK_ColorBLACK);
53 static const SkPMColor kWhite = SkPreMultiplyColor(SK_ColorWHITE);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000054
reed@google.comeb9a46c2014-01-25 16:46:20 +000055 result->allocN32Pixels(width, height, true);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000056
skia.committer@gmail.com956b3102013-07-26 07:00:58 +000057 SkPMColor* scanline = result->getAddr32(0, 0);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000058 for (int x = 0; x < width; ++x) {
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +000059 scanline[x] = kBlue;
60 }
61 scanline = result->getAddr32(0, 1);
62 scanline[0] = kBlue;
63 for (int x = 1; x < width - 1; ++x) {
64 scanline[x] = kRed;
65 }
66 scanline[width-1] = kBlue;
67
68 for (int y = 2; y < height/2; ++y) {
69 scanline = result->getAddr32(0, y);
70 scanline[0] = kBlue;
71 scanline[1] = kRed;
72 for (int x = 2; x < width/2; ++x) {
73 scanline[x] = kBlack;
74 }
75 for (int x = width/2; x < width-2; ++x) {
76 scanline[x] = kWhite;
77 }
78 scanline[width-2] = kRed;
79 scanline[width-1] = kBlue;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000080 }
81
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +000082 for (int y = height/2; y < height-2; ++y) {
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000083 scanline = result->getAddr32(0, y);
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +000084 scanline[0] = kBlue;
85 scanline[1] = kRed;
86 for (int x = 2; x < width/2; ++x) {
87 scanline[x] = kWhite;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000088 }
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +000089 for (int x = width/2; x < width-2; ++x) {
90 scanline[x] = kBlack;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000091 }
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +000092 scanline[width-2] = kRed;
93 scanline[width-1] = kBlue;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000094 }
95
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +000096 scanline = result->getAddr32(0, height-2);
97 scanline[0] = kBlue;
98 for (int x = 1; x < width - 1; ++x) {
99 scanline[x] = kRed;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000100 }
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000101 scanline[width-1] = kBlue;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000102
103 scanline = result->getAddr32(0, height-1);
104 for (int x = 0; x < width; ++x) {
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000105 scanline[x] = kBlue;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000106 }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000107 result->setImmutable();
108}
109
reeda5517e22015-07-14 10:54:12 -0700110// This GM exercises the drawBitmapRect constraints
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000111class BleedGM : public skiagm::GM {
112public:
reeda5517e22015-07-14 10:54:12 -0700113 BleedGM(BleedTest bt) : fBT(bt) {}
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000114
115protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000116
mtklein36352bf2015-03-25 18:17:31 -0700117 SkString onShortName() override {
reeda5517e22015-07-14 10:54:12 -0700118 return SkString(gBleedRec[fBT].fName);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000119 }
120
mtklein36352bf2015-03-25 18:17:31 -0700121 SkISize onISize() override {
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000122 return SkISize::Make(kWidth, 780);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000123 }
124
mtklein36352bf2015-03-25 18:17:31 -0700125 void onOnceBeforeDraw() override {
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000126 make_ringed_bitmap(&fBitmapSmall, kSmallTextureSize, kSmallTextureSize);
reeda5517e22015-07-14 10:54:12 -0700127 fImageSmall.reset(SkImage::NewFromBitmap(fBitmapSmall));
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000128
129 // To exercise the GPU's tiling path we need a texture
130 // too big for the GPU to handle in one go
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000131 make_ringed_bitmap(&fBitmapBig, 2*kMaxTextureSize, 2*kMaxTextureSize);
reeda5517e22015-07-14 10:54:12 -0700132 fImageBig.reset(SkImage::NewFromBitmap(fBitmapBig));
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000133 }
134
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000135 // Draw only the center of the small bitmap
skia.committer@gmail.comb74bdf02013-08-21 07:01:29 +0000136 void drawCase1(SkCanvas* canvas, int transX, int transY,
reeda5517e22015-07-14 10:54:12 -0700137 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000138 SkRect src = SkRect::MakeXYWH(2, 2,
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000139 SkIntToScalar(kSmallTextureSize-4),
140 SkIntToScalar(kSmallTextureSize-4));
reeda5517e22015-07-14 10:54:12 -0700141 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
142 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000143
144 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700145 paint.setFilterQuality(filter);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000146
reede47829b2015-08-06 10:02:53 -0700147 gBleedRec[fBT].fDraw(canvas, fBitmapSmall, fImageSmall, src, dst, &paint, constraint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000148 }
149
150 // Draw almost all of the large bitmap
skia.committer@gmail.comb74bdf02013-08-21 07:01:29 +0000151 void drawCase2(SkCanvas* canvas, int transX, int transY,
reeda5517e22015-07-14 10:54:12 -0700152 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000153 SkRect src = SkRect::MakeXYWH(2, 2,
154 SkIntToScalar(fBitmapBig.width()-4),
155 SkIntToScalar(fBitmapBig.height()-4));
reeda5517e22015-07-14 10:54:12 -0700156 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
157 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000158
159 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700160 paint.setFilterQuality(filter);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000161
reede47829b2015-08-06 10:02:53 -0700162 gBleedRec[fBT].fDraw(canvas, fBitmapBig, fImageBig, src, dst, &paint, constraint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000163 }
164
165 // Draw ~1/4 of the large bitmap
skia.committer@gmail.comb74bdf02013-08-21 07:01:29 +0000166 void drawCase3(SkCanvas* canvas, int transX, int transY,
reeda5517e22015-07-14 10:54:12 -0700167 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000168 SkRect src = SkRect::MakeXYWH(2, 2,
169 SkIntToScalar(fBitmapBig.width()/2-2),
170 SkIntToScalar(fBitmapBig.height()/2-2));
reeda5517e22015-07-14 10:54:12 -0700171 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
172 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000173
174 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700175 paint.setFilterQuality(filter);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000176
reede47829b2015-08-06 10:02:53 -0700177 gBleedRec[fBT].fDraw(canvas, fBitmapBig, fImageBig, src, dst, &paint, constraint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000178 }
179
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000180 // Draw the center of the small bitmap with a mask filter
skia.committer@gmail.comb74bdf02013-08-21 07:01:29 +0000181 void drawCase4(SkCanvas* canvas, int transX, int transY,
reeda5517e22015-07-14 10:54:12 -0700182 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000183 SkRect src = SkRect::MakeXYWH(2, 2,
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000184 SkIntToScalar(kSmallTextureSize-4),
185 SkIntToScalar(kSmallTextureSize-4));
reeda5517e22015-07-14 10:54:12 -0700186 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
187 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000188
189 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700190 paint.setFilterQuality(filter);
commit-bot@chromium.orge3964552014-04-28 16:25:35 +0000191 SkMaskFilter* mf = SkBlurMaskFilter::Create(kNormal_SkBlurStyle,
reeda5517e22015-07-14 10:54:12 -0700192 SkBlurMask::ConvertRadiusToSigma(3));
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000193 paint.setMaskFilter(mf)->unref();
194
reede47829b2015-08-06 10:02:53 -0700195 gBleedRec[fBT].fDraw(canvas, fBitmapSmall, fImageSmall, src, dst, &paint, constraint);
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000196 }
197
mtklein36352bf2015-03-25 18:17:31 -0700198 void onDraw(SkCanvas* canvas) override {
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000199
200 canvas->clear(SK_ColorGRAY);
201
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000202 for (int m = 0; m < 2; ++m) {
203 canvas->save();
204 if (m) {
205 static const SkScalar kBottom = SkIntToScalar(kRow3Y + kBlockSize + kBlockSpacing);
206 canvas->translate(0, kBottom);
207 SkMatrix rotate;
208 rotate.setRotate(15.f, 0, kBottom + kBlockSpacing);
209 canvas->concat(rotate);
210 canvas->scale(0.71f, 1.22f);
211 }
skia.committer@gmail.comed000842013-11-09 07:02:23 +0000212
bsalomon4ee6bd82015-05-27 13:23:23 -0700213 // First draw a column with no bleeding and no filtering
reeda5517e22015-07-14 10:54:12 -0700214 this->drawCase1(canvas, kCol0X, kRow0Y, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
215 this->drawCase2(canvas, kCol0X, kRow1Y, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
216 this->drawCase3(canvas, kCol0X, kRow2Y, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
217 this->drawCase4(canvas, kCol0X, kRow3Y, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000218
bsalomon4ee6bd82015-05-27 13:23:23 -0700219 // Then draw a column with no bleeding and low filtering
reeda5517e22015-07-14 10:54:12 -0700220 this->drawCase1(canvas, kCol1X, kRow0Y, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
221 this->drawCase2(canvas, kCol1X, kRow1Y, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
222 this->drawCase3(canvas, kCol1X, kRow2Y, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
223 this->drawCase4(canvas, kCol1X, kRow3Y, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000224
bsalomon4ee6bd82015-05-27 13:23:23 -0700225 // Then draw a column with no bleeding and high filtering
reeda5517e22015-07-14 10:54:12 -0700226 this->drawCase1(canvas, kCol2X, kRow0Y, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
227 this->drawCase2(canvas, kCol2X, kRow1Y, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
228 this->drawCase3(canvas, kCol2X, kRow2Y, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
229 this->drawCase4(canvas, kCol2X, kRow3Y, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
skia.committer@gmail.comed000842013-11-09 07:02:23 +0000230
bsalomon4ee6bd82015-05-27 13:23:23 -0700231 // Then draw a column with bleeding and no filtering (bleed should have no effect w/out blur)
reeda5517e22015-07-14 10:54:12 -0700232 this->drawCase1(canvas, kCol3X, kRow0Y, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
233 this->drawCase2(canvas, kCol3X, kRow1Y, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
234 this->drawCase3(canvas, kCol3X, kRow2Y, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
235 this->drawCase4(canvas, kCol3X, kRow3Y, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
skia.committer@gmail.com956b3102013-07-26 07:00:58 +0000236
bsalomon4ee6bd82015-05-27 13:23:23 -0700237 // Then draw a column with bleeding and low filtering
reeda5517e22015-07-14 10:54:12 -0700238 this->drawCase1(canvas, kCol4X, kRow0Y, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
239 this->drawCase2(canvas, kCol4X, kRow1Y, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
240 this->drawCase3(canvas, kCol4X, kRow2Y, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
241 this->drawCase4(canvas, kCol4X, kRow3Y, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000242
bsalomon4ee6bd82015-05-27 13:23:23 -0700243 // Finally draw a column with bleeding and high filtering
reeda5517e22015-07-14 10:54:12 -0700244 this->drawCase1(canvas, kCol5X, kRow0Y, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
245 this->drawCase2(canvas, kCol5X, kRow1Y, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
246 this->drawCase3(canvas, kCol5X, kRow2Y, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
247 this->drawCase4(canvas, kCol5X, kRow3Y, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
skia.committer@gmail.comed000842013-11-09 07:02:23 +0000248
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000249 canvas->restore();
250 }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000251 }
252
bsalomon4ee6bd82015-05-27 13:23:23 -0700253#if SK_SUPPORT_GPU
254 void modifyGrContextOptions(GrContextOptions* options) override {
255 options->fMaxTextureSizeOverride = kMaxTextureSize;
256 }
257#endif
258
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000259private:
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000260 static const int kBlockSize = 70;
261 static const int kBlockSpacing = 5;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000262
263 static const int kCol0X = kBlockSpacing;
264 static const int kCol1X = 2*kBlockSpacing + kBlockSize;
265 static const int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
266 static const int kCol3X = 4*kBlockSpacing + 3*kBlockSize;
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000267 static const int kCol4X = 5*kBlockSpacing + 4*kBlockSize;
268 static const int kCol5X = 6*kBlockSpacing + 5*kBlockSize;
bsalomon4ee6bd82015-05-27 13:23:23 -0700269 static const int kWidth = 7*kBlockSpacing + 6*kBlockSize;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000270
271 static const int kRow0Y = kBlockSpacing;
272 static const int kRow1Y = 2*kBlockSpacing + kBlockSize;
273 static const int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000274 static const int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000275
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000276 static const int kSmallTextureSize = 6;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000277 static const int kMaxTextureSize = 32;
278
279 SkBitmap fBitmapSmall;
280 SkBitmap fBitmapBig;
reeda5517e22015-07-14 10:54:12 -0700281 SkAutoTUnref<SkImage> fImageSmall;
282 SkAutoTUnref<SkImage> fImageBig;
283 const BleedTest fBT;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000284
285 typedef GM INHERITED;
286};
287
reeda5517e22015-07-14 10:54:12 -0700288DEF_GM( return new BleedGM(kUseBitmap_BleedTest); )
289DEF_GM( return new BleedGM(kUseImage_BleedTest); )