1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2018 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "gm/gm.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBlendMode.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorFilter.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTileMode.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkGradientShader.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrDirectContext.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "tools/GpuToolUtils.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ToolUtils.h"
32*c8dee2aaSAndroid Build Coastguard Worker
33*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
34*c8dee2aaSAndroid Build Coastguard Worker #include <initializer_list>
35*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
36*c8dee2aaSAndroid Build Coastguard Worker
37*c8dee2aaSAndroid Build Coastguard Worker // Makes a set of m x n tiled images to be drawn with SkCanvas::experimental_drawImageSetV1().
make_image_tiles(int tileW,int tileH,int m,int n,const SkColor colors[4],SkCanvas::ImageSetEntry set[],const SkColor bgColor=SK_ColorLTGRAY)38*c8dee2aaSAndroid Build Coastguard Worker static void make_image_tiles(int tileW, int tileH, int m, int n, const SkColor colors[4],
39*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::ImageSetEntry set[], const SkColor bgColor=SK_ColorLTGRAY) {
40*c8dee2aaSAndroid Build Coastguard Worker const int w = tileW * m;
41*c8dee2aaSAndroid Build Coastguard Worker const int h = tileH * n;
42*c8dee2aaSAndroid Build Coastguard Worker auto surf = SkSurfaces::Raster(
43*c8dee2aaSAndroid Build Coastguard Worker SkImageInfo::Make(w, h, kRGBA_8888_SkColorType, kPremul_SkAlphaType));
44*c8dee2aaSAndroid Build Coastguard Worker surf->getCanvas()->clear(bgColor);
45*c8dee2aaSAndroid Build Coastguard Worker
46*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kStripeW = 10;
47*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kStripeSpacing = 30;
48*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
49*c8dee2aaSAndroid Build Coastguard Worker
50*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts1[] = {{0.f, 0.f}, {(SkScalar)w, (SkScalar)h}};
51*c8dee2aaSAndroid Build Coastguard Worker auto grad = SkGradientShader::MakeLinear(pts1, colors, nullptr, 2, SkTileMode::kClamp);
52*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(std::move(grad));
53*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
54*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(SkPaint::kStroke_Style);
55*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeWidth(kStripeW);
56*c8dee2aaSAndroid Build Coastguard Worker SkPoint stripePts[] = {{-w - kStripeW, -kStripeW}, {kStripeW, h + kStripeW}};
57*c8dee2aaSAndroid Build Coastguard Worker while (stripePts[0].fX <= w) {
58*c8dee2aaSAndroid Build Coastguard Worker surf->getCanvas()->drawPoints(SkCanvas::kLines_PointMode, 2, stripePts, paint);
59*c8dee2aaSAndroid Build Coastguard Worker stripePts[0].fX += kStripeSpacing;
60*c8dee2aaSAndroid Build Coastguard Worker stripePts[1].fX += kStripeSpacing;
61*c8dee2aaSAndroid Build Coastguard Worker }
62*c8dee2aaSAndroid Build Coastguard Worker
63*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts2[] = {{0.f, (SkScalar)h}, {(SkScalar)w, 0.f}};
64*c8dee2aaSAndroid Build Coastguard Worker grad = SkGradientShader::MakeLinear(pts2, colors + 2, nullptr, 2, SkTileMode::kClamp);
65*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(std::move(grad));
66*c8dee2aaSAndroid Build Coastguard Worker paint.setBlendMode(SkBlendMode::kMultiply);
67*c8dee2aaSAndroid Build Coastguard Worker stripePts[0] = {-w - kStripeW, h + kStripeW};
68*c8dee2aaSAndroid Build Coastguard Worker stripePts[1] = {kStripeW, -kStripeW};
69*c8dee2aaSAndroid Build Coastguard Worker while (stripePts[0].fX <= w) {
70*c8dee2aaSAndroid Build Coastguard Worker surf->getCanvas()->drawPoints(SkCanvas::kLines_PointMode, 2, stripePts, paint);
71*c8dee2aaSAndroid Build Coastguard Worker stripePts[0].fX += kStripeSpacing;
72*c8dee2aaSAndroid Build Coastguard Worker stripePts[1].fX += kStripeSpacing;
73*c8dee2aaSAndroid Build Coastguard Worker }
74*c8dee2aaSAndroid Build Coastguard Worker auto fullImage = surf->makeImageSnapshot();
75*c8dee2aaSAndroid Build Coastguard Worker for (int y = 0; y < n; ++y) {
76*c8dee2aaSAndroid Build Coastguard Worker for (int x = 0; x < m; ++x) {
77*c8dee2aaSAndroid Build Coastguard Worker // Images will have 1 pixel of overlap at interior seams for filtering continuity.
78*c8dee2aaSAndroid Build Coastguard Worker SkIRect subset = SkIRect::MakeXYWH(x * tileW - 1, y * tileH - 1, tileW + 2, tileH + 2);
79*c8dee2aaSAndroid Build Coastguard Worker set[y * m + x].fAAFlags = SkCanvas::kNone_QuadAAFlags;
80*c8dee2aaSAndroid Build Coastguard Worker if (x == 0) {
81*c8dee2aaSAndroid Build Coastguard Worker subset.fLeft = 0;
82*c8dee2aaSAndroid Build Coastguard Worker set[y * m + x].fAAFlags |= SkCanvas::kLeft_QuadAAFlag;
83*c8dee2aaSAndroid Build Coastguard Worker }
84*c8dee2aaSAndroid Build Coastguard Worker if (x == m - 1) {
85*c8dee2aaSAndroid Build Coastguard Worker subset.fRight = w;
86*c8dee2aaSAndroid Build Coastguard Worker set[y * m + x].fAAFlags |= SkCanvas::kRight_QuadAAFlag;
87*c8dee2aaSAndroid Build Coastguard Worker }
88*c8dee2aaSAndroid Build Coastguard Worker if (y == 0) {
89*c8dee2aaSAndroid Build Coastguard Worker subset.fTop = 0;
90*c8dee2aaSAndroid Build Coastguard Worker set[y * m + x].fAAFlags |= SkCanvas::kTop_QuadAAFlag;
91*c8dee2aaSAndroid Build Coastguard Worker }
92*c8dee2aaSAndroid Build Coastguard Worker if (y == n - 1) {
93*c8dee2aaSAndroid Build Coastguard Worker subset.fBottom = h;
94*c8dee2aaSAndroid Build Coastguard Worker set[y * m + x].fAAFlags |= SkCanvas::kBottom_QuadAAFlag;
95*c8dee2aaSAndroid Build Coastguard Worker }
96*c8dee2aaSAndroid Build Coastguard Worker set[y * m + x].fImage = fullImage->makeSubset(nullptr, subset);
97*c8dee2aaSAndroid Build Coastguard Worker set[y * m + x].fSrcRect =
98*c8dee2aaSAndroid Build Coastguard Worker SkRect::MakeXYWH(x == 0 ? 0 : 1, y == 0 ? 0 : 1, tileW, tileH);
99*c8dee2aaSAndroid Build Coastguard Worker set[y * m + x].fDstRect = SkRect::MakeXYWH(x * tileW, y * tileH, tileW, tileH);
100*c8dee2aaSAndroid Build Coastguard Worker set[y * m + x].fAlpha = 1.f;
101*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(set[y * m + x].fImage);
102*c8dee2aaSAndroid Build Coastguard Worker }
103*c8dee2aaSAndroid Build Coastguard Worker }
104*c8dee2aaSAndroid Build Coastguard Worker }
105*c8dee2aaSAndroid Build Coastguard Worker
106*c8dee2aaSAndroid Build Coastguard Worker namespace skiagm {
107*c8dee2aaSAndroid Build Coastguard Worker
108*c8dee2aaSAndroid Build Coastguard Worker class DrawImageSetGM : public GM {
109*c8dee2aaSAndroid Build Coastguard Worker private:
getName() const110*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override { return SkString("draw_image_set"); }
getISize()111*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return {1000, 725}; }
onOnceBeforeDraw()112*c8dee2aaSAndroid Build Coastguard Worker void onOnceBeforeDraw() override {
113*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkColor kColors[] = {SK_ColorCYAN, SK_ColorBLACK,
114*c8dee2aaSAndroid Build Coastguard Worker SK_ColorMAGENTA, SK_ColorBLACK};
115*c8dee2aaSAndroid Build Coastguard Worker make_image_tiles(kTileW, kTileH, kM, kN, kColors, fSet);
116*c8dee2aaSAndroid Build Coastguard Worker }
117*c8dee2aaSAndroid Build Coastguard Worker
onDraw(SkCanvas * canvas)118*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override {
119*c8dee2aaSAndroid Build Coastguard Worker SkScalar d = SkVector{kM * kTileW, kN * kTileH}.length();
120*c8dee2aaSAndroid Build Coastguard Worker SkMatrix matrices[4];
121*c8dee2aaSAndroid Build Coastguard Worker // rotation
122*c8dee2aaSAndroid Build Coastguard Worker matrices[0].setRotate(30);
123*c8dee2aaSAndroid Build Coastguard Worker matrices[0].postTranslate(d / 3, 0);
124*c8dee2aaSAndroid Build Coastguard Worker // perespective
125*c8dee2aaSAndroid Build Coastguard Worker SkPoint src[4];
126*c8dee2aaSAndroid Build Coastguard Worker SkRect::MakeWH(kM * kTileW, kN * kTileH).toQuad(src);
127*c8dee2aaSAndroid Build Coastguard Worker SkPoint dst[4] = {{0, 0},
128*c8dee2aaSAndroid Build Coastguard Worker {kM * kTileW + 10.f, -5.f},
129*c8dee2aaSAndroid Build Coastguard Worker {kM * kTileW - 28.f, kN * kTileH + 40.f},
130*c8dee2aaSAndroid Build Coastguard Worker {45.f, kN * kTileH - 25.f}};
131*c8dee2aaSAndroid Build Coastguard Worker SkAssertResult(matrices[1].setPolyToPoly(src, dst, 4));
132*c8dee2aaSAndroid Build Coastguard Worker matrices[1].postTranslate(d, 50.f);
133*c8dee2aaSAndroid Build Coastguard Worker // skew
134*c8dee2aaSAndroid Build Coastguard Worker matrices[2].setRotate(-60.f);
135*c8dee2aaSAndroid Build Coastguard Worker matrices[2].postSkew(0.5f, -1.15f);
136*c8dee2aaSAndroid Build Coastguard Worker matrices[2].postScale(0.6f, 1.05f);
137*c8dee2aaSAndroid Build Coastguard Worker matrices[2].postTranslate(d, 2.6f * d);
138*c8dee2aaSAndroid Build Coastguard Worker // perspective + mirror in x.
139*c8dee2aaSAndroid Build Coastguard Worker dst[1] = {-.25 * kM * kTileW, 0};
140*c8dee2aaSAndroid Build Coastguard Worker dst[0] = {5.f / 4.f * kM * kTileW, 0};
141*c8dee2aaSAndroid Build Coastguard Worker dst[3] = {2.f / 3.f * kM * kTileW, 1 / 2.f * kN * kTileH};
142*c8dee2aaSAndroid Build Coastguard Worker dst[2] = {1.f / 3.f * kM * kTileW, 1 / 2.f * kN * kTileH - 0.1f * kTileH};
143*c8dee2aaSAndroid Build Coastguard Worker SkAssertResult(matrices[3].setPolyToPoly(src, dst, 4));
144*c8dee2aaSAndroid Build Coastguard Worker matrices[3].postTranslate(100.f, d);
145*c8dee2aaSAndroid Build Coastguard Worker for (auto fm : {SkFilterMode::kNearest, SkFilterMode::kLinear}) {
146*c8dee2aaSAndroid Build Coastguard Worker SkPaint setPaint;
147*c8dee2aaSAndroid Build Coastguard Worker setPaint.setBlendMode(SkBlendMode::kSrcOver);
148*c8dee2aaSAndroid Build Coastguard Worker SkSamplingOptions sampling(fm);
149*c8dee2aaSAndroid Build Coastguard Worker
150*c8dee2aaSAndroid Build Coastguard Worker for (size_t m = 0; m < std::size(matrices); ++m) {
151*c8dee2aaSAndroid Build Coastguard Worker // Draw grid of red lines at interior tile boundaries.
152*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kLineOutset = 10.f;
153*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
154*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
155*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(SK_ColorRED);
156*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(SkPaint::kStroke_Style);
157*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeWidth(0.f);
158*c8dee2aaSAndroid Build Coastguard Worker for (int x = 1; x < kM; ++x) {
159*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts[] = {{x * kTileW, 0}, {x * kTileW, kN * kTileH}};
160*c8dee2aaSAndroid Build Coastguard Worker matrices[m].mapPoints(pts, 2);
161*c8dee2aaSAndroid Build Coastguard Worker SkVector v = pts[1] - pts[0];
162*c8dee2aaSAndroid Build Coastguard Worker v.setLength(v.length() + kLineOutset);
163*c8dee2aaSAndroid Build Coastguard Worker canvas->drawLine(pts[1] - v, pts[0] + v, paint);
164*c8dee2aaSAndroid Build Coastguard Worker }
165*c8dee2aaSAndroid Build Coastguard Worker for (int y = 1; y < kN; ++y) {
166*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts[] = {{0, y * kTileH}, {kTileW * kM, y * kTileH}};
167*c8dee2aaSAndroid Build Coastguard Worker matrices[m].mapPoints(pts, 2);
168*c8dee2aaSAndroid Build Coastguard Worker SkVector v = pts[1] - pts[0];
169*c8dee2aaSAndroid Build Coastguard Worker v.setLength(v.length() + kLineOutset);
170*c8dee2aaSAndroid Build Coastguard Worker canvas->drawLine(pts[1] - v, pts[0] + v, paint);
171*c8dee2aaSAndroid Build Coastguard Worker }
172*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
173*c8dee2aaSAndroid Build Coastguard Worker canvas->concat(matrices[m]);
174*c8dee2aaSAndroid Build Coastguard Worker canvas->experimental_DrawEdgeAAImageSet(fSet, kM * kN, nullptr, nullptr, sampling,
175*c8dee2aaSAndroid Build Coastguard Worker &setPaint,
176*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::kFast_SrcRectConstraint);
177*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
178*c8dee2aaSAndroid Build Coastguard Worker }
179*c8dee2aaSAndroid Build Coastguard Worker // A more exotic case with an unusual blend mode, mixed aa flags set, and alpha,
180*c8dee2aaSAndroid Build Coastguard Worker // subsets the image. And another with all the above plus a color filter.
181*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::ImageSetEntry entry;
182*c8dee2aaSAndroid Build Coastguard Worker entry.fSrcRect = SkRect::MakeWH(kTileW, kTileH).makeInset(kTileW / 4.f, kTileH / 4.f);
183*c8dee2aaSAndroid Build Coastguard Worker entry.fDstRect = SkRect::MakeWH(1.5 * kTileW, 1.5 * kTileH).makeOffset(d / 4, 2 * d);
184*c8dee2aaSAndroid Build Coastguard Worker entry.fImage = fSet[0].fImage;
185*c8dee2aaSAndroid Build Coastguard Worker entry.fAlpha = 0.7f;
186*c8dee2aaSAndroid Build Coastguard Worker entry.fAAFlags = SkCanvas::kLeft_QuadAAFlag | SkCanvas::kTop_QuadAAFlag;
187*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
188*c8dee2aaSAndroid Build Coastguard Worker canvas->rotate(3.f);
189*c8dee2aaSAndroid Build Coastguard Worker
190*c8dee2aaSAndroid Build Coastguard Worker setPaint.setBlendMode(SkBlendMode::kExclusion);
191*c8dee2aaSAndroid Build Coastguard Worker canvas->experimental_DrawEdgeAAImageSet(&entry, 1, nullptr, nullptr, sampling,
192*c8dee2aaSAndroid Build Coastguard Worker &setPaint, SkCanvas::kFast_SrcRectConstraint);
193*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(entry.fDstRect.width() + 8.f, 0);
194*c8dee2aaSAndroid Build Coastguard Worker SkPaint cfPaint = setPaint;
195*c8dee2aaSAndroid Build Coastguard Worker cfPaint.setColorFilter(SkColorFilters::LinearToSRGBGamma());
196*c8dee2aaSAndroid Build Coastguard Worker canvas->experimental_DrawEdgeAAImageSet(&entry, 1, nullptr, nullptr, sampling,
197*c8dee2aaSAndroid Build Coastguard Worker &cfPaint, SkCanvas::kFast_SrcRectConstraint);
198*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
199*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(2 * d, 0);
200*c8dee2aaSAndroid Build Coastguard Worker }
201*c8dee2aaSAndroid Build Coastguard Worker }
202*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kM = 4;
203*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kN = 3;
204*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr SkScalar kTileW = 30;
205*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr SkScalar kTileH = 60;
206*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::ImageSetEntry fSet[kM * kN];
207*c8dee2aaSAndroid Build Coastguard Worker };
208*c8dee2aaSAndroid Build Coastguard Worker
209*c8dee2aaSAndroid Build Coastguard Worker // This GM exercises rect-stays-rect type matrices to test that filtering and antialiasing are not
210*c8dee2aaSAndroid Build Coastguard Worker // incorrectly disabled.
211*c8dee2aaSAndroid Build Coastguard Worker class DrawImageSetRectToRectGM : public GM {
212*c8dee2aaSAndroid Build Coastguard Worker private:
getName() const213*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override { return SkString("draw_image_set_rect_to_rect"); }
getISize()214*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return {1250, 850}; }
onOnceBeforeDraw()215*c8dee2aaSAndroid Build Coastguard Worker void onOnceBeforeDraw() override {
216*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkColor kColors[] = {SK_ColorBLUE, SK_ColorWHITE,
217*c8dee2aaSAndroid Build Coastguard Worker SK_ColorRED, SK_ColorWHITE};
218*c8dee2aaSAndroid Build Coastguard Worker make_image_tiles(kTileW, kTileH, kM, kN, kColors, fSet);
219*c8dee2aaSAndroid Build Coastguard Worker }
220*c8dee2aaSAndroid Build Coastguard Worker
onDraw(SkCanvas * canvas)221*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override {
222*c8dee2aaSAndroid Build Coastguard Worker ToolUtils::draw_checkerboard(canvas, SK_ColorBLACK, SK_ColorWHITE, 50);
223*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kW = kM * kTileW;
224*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kH = kN * kTileH;
225*c8dee2aaSAndroid Build Coastguard Worker SkMatrix matrices[5];
226*c8dee2aaSAndroid Build Coastguard Worker // Identity
227*c8dee2aaSAndroid Build Coastguard Worker matrices[0].reset();
228*c8dee2aaSAndroid Build Coastguard Worker // 90 degree rotation
229*c8dee2aaSAndroid Build Coastguard Worker matrices[1].setRotate(90, kW / 2.f, kH / 2.f);
230*c8dee2aaSAndroid Build Coastguard Worker // Scaling
231*c8dee2aaSAndroid Build Coastguard Worker matrices[2].setScale(2.f, 0.5f);
232*c8dee2aaSAndroid Build Coastguard Worker // Mirror in x and y
233*c8dee2aaSAndroid Build Coastguard Worker matrices[3].setScale(-1.f, -1.f);
234*c8dee2aaSAndroid Build Coastguard Worker matrices[3].postTranslate(kW, kH);
235*c8dee2aaSAndroid Build Coastguard Worker // Mirror in y, rotate, and scale.
236*c8dee2aaSAndroid Build Coastguard Worker matrices[4].setScale(1.f, -1.f);
237*c8dee2aaSAndroid Build Coastguard Worker matrices[4].postTranslate(0, kH);
238*c8dee2aaSAndroid Build Coastguard Worker matrices[4].postRotate(90, kW / 2.f, kH / 2.f);
239*c8dee2aaSAndroid Build Coastguard Worker matrices[4].postScale(2.f, 0.5f);
240*c8dee2aaSAndroid Build Coastguard Worker
241*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
242*c8dee2aaSAndroid Build Coastguard Worker paint.setBlendMode(SkBlendMode::kSrcOver);
243*c8dee2aaSAndroid Build Coastguard Worker
244*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kTranslate = std::max(kW, kH) * 2.f + 10.f;
245*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(5.f, 5.f);
246*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
247*c8dee2aaSAndroid Build Coastguard Worker for (SkScalar frac : {0.f, 0.5f}) {
248*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
249*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(frac, frac);
250*c8dee2aaSAndroid Build Coastguard Worker for (size_t m = 0; m < std::size(matrices); ++m) {
251*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
252*c8dee2aaSAndroid Build Coastguard Worker canvas->concat(matrices[m]);
253*c8dee2aaSAndroid Build Coastguard Worker canvas->experimental_DrawEdgeAAImageSet(fSet, kM * kN, nullptr, nullptr,
254*c8dee2aaSAndroid Build Coastguard Worker SkSamplingOptions(SkFilterMode::kLinear),
255*c8dee2aaSAndroid Build Coastguard Worker &paint, SkCanvas::kFast_SrcRectConstraint);
256*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
257*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(kTranslate, 0);
258*c8dee2aaSAndroid Build Coastguard Worker }
259*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
260*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
261*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, kTranslate);
262*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
263*c8dee2aaSAndroid Build Coastguard Worker }
264*c8dee2aaSAndroid Build Coastguard Worker for (SkVector scale : {SkVector{2.f, 0.5f}, SkVector{0.5, 2.f}}) {
265*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::ImageSetEntry scaledSet[kM * kN];
266*c8dee2aaSAndroid Build Coastguard Worker std::copy_n(fSet, kM * kN, scaledSet);
267*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < kM * kN; ++i) {
268*c8dee2aaSAndroid Build Coastguard Worker scaledSet[i].fDstRect.fLeft *= scale.fX;
269*c8dee2aaSAndroid Build Coastguard Worker scaledSet[i].fDstRect.fTop *= scale.fY;
270*c8dee2aaSAndroid Build Coastguard Worker scaledSet[i].fDstRect.fRight *= scale.fX;
271*c8dee2aaSAndroid Build Coastguard Worker scaledSet[i].fDstRect.fBottom *= scale.fY;
272*c8dee2aaSAndroid Build Coastguard Worker scaledSet[i].fAlpha = 0 == (i % 3) ? 0.4f : 1.f;
273*c8dee2aaSAndroid Build Coastguard Worker }
274*c8dee2aaSAndroid Build Coastguard Worker for (size_t m = 0; m < std::size(matrices); ++m) {
275*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
276*c8dee2aaSAndroid Build Coastguard Worker canvas->concat(matrices[m]);
277*c8dee2aaSAndroid Build Coastguard Worker canvas->experimental_DrawEdgeAAImageSet(scaledSet, kM * kN, nullptr, nullptr,
278*c8dee2aaSAndroid Build Coastguard Worker SkSamplingOptions(SkFilterMode::kLinear),
279*c8dee2aaSAndroid Build Coastguard Worker &paint, SkCanvas::kFast_SrcRectConstraint);
280*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
281*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(kTranslate, 0);
282*c8dee2aaSAndroid Build Coastguard Worker }
283*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
284*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, kTranslate);
285*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
286*c8dee2aaSAndroid Build Coastguard Worker }
287*c8dee2aaSAndroid Build Coastguard Worker }
288*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kM = 2;
289*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kN = 2;
290*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kTileW = 40;
291*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kTileH = 50;
292*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::ImageSetEntry fSet[kM * kN];
293*c8dee2aaSAndroid Build Coastguard Worker };
294*c8dee2aaSAndroid Build Coastguard Worker
295*c8dee2aaSAndroid Build Coastguard Worker // This GM exercises alpha-only and color textures being combined correctly with the paint's color.
296*c8dee2aaSAndroid Build Coastguard Worker class DrawImageSetAlphaOnlyGM : public GM {
297*c8dee2aaSAndroid Build Coastguard Worker private:
getName() const298*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override { return SkString("draw_image_set_alpha_only"); }
getISize()299*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return {kM * kTileW, 2 * kN * kTileH}; }
300*c8dee2aaSAndroid Build Coastguard Worker
onGpuSetup(SkCanvas * canvas,SkString *,GraphiteTestContext *)301*c8dee2aaSAndroid Build Coastguard Worker DrawResult onGpuSetup(SkCanvas* canvas, SkString*, GraphiteTestContext*) override {
302*c8dee2aaSAndroid Build Coastguard Worker auto direct = GrAsDirectContext(canvas->recordingContext());
303*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GRAPHITE)
304*c8dee2aaSAndroid Build Coastguard Worker auto recorder = canvas->recorder();
305*c8dee2aaSAndroid Build Coastguard Worker #endif
306*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkColor kColors[] = {SK_ColorBLUE, SK_ColorTRANSPARENT,
307*c8dee2aaSAndroid Build Coastguard Worker SK_ColorRED, SK_ColorTRANSPARENT};
308*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkColor kBGColor = SkColorSetARGB(128, 128, 128, 128);
309*c8dee2aaSAndroid Build Coastguard Worker make_image_tiles(kTileW, kTileH, kM, kN, kColors, fSet, kBGColor);
310*c8dee2aaSAndroid Build Coastguard Worker
311*c8dee2aaSAndroid Build Coastguard Worker // Modify the alpha of the entries, decreasing by column, and convert even rows to
312*c8dee2aaSAndroid Build Coastguard Worker // alpha-only textures.
313*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkColorSpace> alphaSpace = SkColorSpace::MakeSRGB();
314*c8dee2aaSAndroid Build Coastguard Worker for (int y = 0; y < kN; ++y) {
315*c8dee2aaSAndroid Build Coastguard Worker for (int x = 0; x < kM; ++x) {
316*c8dee2aaSAndroid Build Coastguard Worker int i = y * kM + x;
317*c8dee2aaSAndroid Build Coastguard Worker fSet[i].fAlpha = (kM - x) / (float) kM;
318*c8dee2aaSAndroid Build Coastguard Worker if (y % 2 == 0) {
319*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GRAPHITE)
320*c8dee2aaSAndroid Build Coastguard Worker if (recorder) {
321*c8dee2aaSAndroid Build Coastguard Worker fSet[i].fImage = fSet[i].fImage->makeColorTypeAndColorSpace(
322*c8dee2aaSAndroid Build Coastguard Worker recorder, kAlpha_8_SkColorType, alphaSpace, {});
323*c8dee2aaSAndroid Build Coastguard Worker } else
324*c8dee2aaSAndroid Build Coastguard Worker #endif
325*c8dee2aaSAndroid Build Coastguard Worker {
326*c8dee2aaSAndroid Build Coastguard Worker fSet[i].fImage = fSet[i].fImage->makeColorTypeAndColorSpace(
327*c8dee2aaSAndroid Build Coastguard Worker direct, kAlpha_8_SkColorType, alphaSpace);
328*c8dee2aaSAndroid Build Coastguard Worker }
329*c8dee2aaSAndroid Build Coastguard Worker }
330*c8dee2aaSAndroid Build Coastguard Worker }
331*c8dee2aaSAndroid Build Coastguard Worker }
332*c8dee2aaSAndroid Build Coastguard Worker return skiagm::DrawResult::kOk;
333*c8dee2aaSAndroid Build Coastguard Worker }
334*c8dee2aaSAndroid Build Coastguard Worker
onDraw(SkCanvas * canvas)335*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override {
336*c8dee2aaSAndroid Build Coastguard Worker ToolUtils::draw_checkerboard(canvas, SK_ColorGRAY, SK_ColorDKGRAY, 25);
337*c8dee2aaSAndroid Build Coastguard Worker
338*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
339*c8dee2aaSAndroid Build Coastguard Worker paint.setBlendMode(SkBlendMode::kSrcOver);
340*c8dee2aaSAndroid Build Coastguard Worker paint.setColor4f({0.2f, 0.8f, 0.4f, 1.f}); // colorizes even rows, no effect on odd rows
341*c8dee2aaSAndroid Build Coastguard Worker
342*c8dee2aaSAndroid Build Coastguard Worker // Top rows use experimental edge set API
343*c8dee2aaSAndroid Build Coastguard Worker canvas->experimental_DrawEdgeAAImageSet(fSet, kM * kN, nullptr, nullptr,
344*c8dee2aaSAndroid Build Coastguard Worker SkSamplingOptions(SkFilterMode::kLinear), &paint,
345*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::kFast_SrcRectConstraint);
346*c8dee2aaSAndroid Build Coastguard Worker
347*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0.f, kN * kTileH);
348*c8dee2aaSAndroid Build Coastguard Worker
349*c8dee2aaSAndroid Build Coastguard Worker // Bottom rows draw each image from the set using the regular API
350*c8dee2aaSAndroid Build Coastguard Worker for (int y = 0; y < kN; ++y) {
351*c8dee2aaSAndroid Build Coastguard Worker for (int x = 0; x < kM; ++x) {
352*c8dee2aaSAndroid Build Coastguard Worker int i = y * kM + x;
353*c8dee2aaSAndroid Build Coastguard Worker SkPaint entryPaint = paint;
354*c8dee2aaSAndroid Build Coastguard Worker entryPaint.setAlphaf(fSet[i].fAlpha * paint.getAlphaf());
355*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> orig = sk_ref_sp(const_cast<SkImage*>(fSet[i].fImage.get()));
356*c8dee2aaSAndroid Build Coastguard Worker canvas->drawImageRect(ToolUtils::MakeTextureImage(canvas, std::move(orig)),
357*c8dee2aaSAndroid Build Coastguard Worker fSet[i].fSrcRect, fSet[i].fDstRect,
358*c8dee2aaSAndroid Build Coastguard Worker SkSamplingOptions(), &entryPaint,
359*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::kFast_SrcRectConstraint);
360*c8dee2aaSAndroid Build Coastguard Worker }
361*c8dee2aaSAndroid Build Coastguard Worker }
362*c8dee2aaSAndroid Build Coastguard Worker }
363*c8dee2aaSAndroid Build Coastguard Worker
364*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kM = 4;
365*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kN = 4;
366*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kTileW = 50;
367*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kTileH = 50;
368*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::ImageSetEntry fSet[kM * kN];
369*c8dee2aaSAndroid Build Coastguard Worker };
370*c8dee2aaSAndroid Build Coastguard Worker
371*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new DrawImageSetGM();)
372*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new DrawImageSetRectToRectGM();)
373*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new DrawImageSetAlphaOnlyGM();)
374*c8dee2aaSAndroid Build Coastguard Worker
375*c8dee2aaSAndroid Build Coastguard Worker } // namespace skiagm
376