1 /*
2 * Copyright 2018 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/gm.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkBlendMode.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkImage.h"
14 #include "include/core/SkImageInfo.h"
15 #include "include/core/SkMatrix.h"
16 #include "include/core/SkPaint.h"
17 #include "include/core/SkRect.h"
18 #include "include/core/SkRefCnt.h"
19 #include "include/core/SkScalar.h"
20 #include "include/core/SkShader.h"
21 #include "include/core/SkSurface.h"
22 #include "include/core/SkTypes.h"
23 #include "include/effects/SkGradientShader.h"
24 #include "tools/Resources.h"
25 #include "tools/ToolUtils.h"
26
make_image(SkCanvas * rootCanvas)27 static sk_sp<SkImage> make_image(SkCanvas* rootCanvas) {
28 static constexpr SkScalar kSize = 50;
29 SkImageInfo info = SkImageInfo::MakeN32Premul(kSize, kSize);
30 auto surface = ToolUtils::makeSurface(rootCanvas, info);
31
32 SkPaint p;
33 p.setAntiAlias(true);
34 p.setColor(SK_ColorGREEN);
35
36 surface->getCanvas()->drawCircle(kSize / 2, kSize / 2, kSize / 2, p);
37
38 p.setStyle(SkPaint::kStroke_Style);
39 p.setColor(SK_ColorRED);
40 surface->getCanvas()->drawLine(kSize * .25f, kSize * .50f, kSize * .75f, kSize * .50f, p);
41 surface->getCanvas()->drawLine(kSize * .50f, kSize * .25f, kSize * .50f, kSize * .75f, p);
42
43 return surface->makeImageSnapshot();
44 }
45
46 DEF_SIMPLE_GM(localmatrixshader_nested, canvas, 450, 1200) {
47 auto image = make_image(canvas);
48
49 using FactoryT = sk_sp<SkShader> (*)(const sk_sp<SkImage>&,
50 const SkMatrix& inner,
51 const SkMatrix& outer);
52 static const FactoryT gFactories[] = {
53 // SkLocalMatrixShader(SkImageShader(inner), outer)
__anoneeba54430102() 54 [](const sk_sp<SkImage>& img, const SkMatrix& inner, const SkMatrix& outer) {
55 return img->makeShader(SkSamplingOptions(), inner)->makeWithLocalMatrix(outer);
56 },
57
58 // SkLocalMatrixShader(SkLocalMatrixShader(SkImageShader(I), inner), outer)
__anoneeba54430202() 59 [](const sk_sp<SkImage>& img, const SkMatrix& inner, const SkMatrix& outer) {
60 return img->makeShader(SkSamplingOptions())->makeWithLocalMatrix(inner)->makeWithLocalMatrix(outer);
61 },
62
63 // SkLocalMatrixShader(SkComposeShader(SkImageShader(inner)), outer)
__anoneeba54430302() 64 [](const sk_sp<SkImage>& img, const SkMatrix& inner, const SkMatrix& outer) {
65 return SkShaders::Blend(SkBlendMode::kSrcOver,
66 SkShaders::Color(SK_ColorTRANSPARENT),
67 img->makeShader(SkSamplingOptions(), inner))
68 ->makeWithLocalMatrix(outer);
69 },
70
71 // SkLocalMatrixShader(SkComposeShader(SkLocalMatrixShader(SkImageShader(I), inner)), outer)
__anoneeba54430402() 72 [](const sk_sp<SkImage>& img, const SkMatrix& inner, const SkMatrix& outer) {
73 return SkShaders::Blend(SkBlendMode::kSrcOver,
74 SkShaders::Color(SK_ColorTRANSPARENT),
75 img->makeShader(SkSamplingOptions())->makeWithLocalMatrix(inner))
76 ->makeWithLocalMatrix(outer);
77 },
78 };
79
80 static const auto inner = SkMatrix::Scale(2, 2),
81 outer = SkMatrix::Translate(20, 20);
82
83 SkPaint border;
84 border.setAntiAlias(true);
85 border.setStyle(SkPaint::kStroke_Style);
86
87 auto rect = SkRect::Make(image->bounds());
88 SkAssertResult(SkMatrix::Concat(inner, outer).mapRect(&rect));
89
__anoneeba54430502() 90 const auto drawColumn = [&]() {
91 SkAutoCanvasRestore acr(canvas, true);
92 for (const auto& f : gFactories) {
93 SkPaint p;
94 p.setShader(f(image, inner, outer));
95
96 canvas->drawRect(rect, p);
97 canvas->drawRect(rect, border);
98
99 canvas->translate(0, rect.height() * 1.5f);
100 }
101 };
102
103 drawColumn();
104
105 {
106 SkAutoCanvasRestore acr(canvas, true);
107 canvas->translate(0, rect.height() * SK_ARRAY_COUNT(gFactories) * 1.5f);
108 drawColumn();
109 }
110
111 canvas->translate(rect.width() * 1.5f, 0);
112 canvas->scale(2, 2);
113 drawColumn();
114 }
115
116 DEF_SIMPLE_GM(localmatrixshader_persp, canvas, 542, 266) {
117 auto image = GetResourceAsImage("images/yellow_rose.png");
118
119 SkBitmap downsized;
120 downsized.allocPixels(image->imageInfo().makeWH(128, 128));
121 image->scalePixels(downsized.pixmap(), SkSamplingOptions(SkFilterMode::kLinear));
122 image = downsized.asImage();
123 SkRect imgRect = SkRect::MakeIWH(image->width(), image->height());
124
125 // scale matrix
126 SkMatrix scale = SkMatrix::Scale(1.f / 5.f, 1.f / 5.f);
127
128 // perspective matrix
129 SkPoint src[4];
130 imgRect.toQuad(src);
131 SkPoint dst[4] = {{0, 10.f},
132 {image->width() + 28.f, -100.f},
133 {image->width() - 28.f, image->height() + 100.f},
134 {0.f, image->height() - 10.f}};
135 SkMatrix persp;
136 SkAssertResult(persp.setPolyToPoly(src, dst, 4));
137
138 // combined persp * scale
139 SkMatrix perspScale = SkMatrix::Concat(persp, scale);
140
__anoneeba54430602(sk_sp<SkShader> shader, bool applyPerspToCTM) 141 auto draw = [&](sk_sp<SkShader> shader, bool applyPerspToCTM) {
142 canvas->save();
143 canvas->clipRect(imgRect);
144 if (applyPerspToCTM) {
145 canvas->concat(persp);
146 }
147 SkPaint imgShaderPaint;
148 imgShaderPaint.setShader(std::move(shader));
149 canvas->drawPaint(imgShaderPaint);
150 canvas->restore();
151
152 canvas->translate(10.f + image->width(), 0.f); // advance
153 };
154
155 // SkImageShader
156 canvas->save();
157 // 4 variants that all attempt to apply sample at persp * scale w/ an image shader
158 // 1. scale provided to SkImage::makeShader(...) but drawn with persp
159 auto s1 = image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat,
160 SkSamplingOptions(), &scale);
161 draw(s1, true);
162
163 // 2. persp provided to SkImage::makeShader, then wrapped in scale makeWithLocalMatrix
164 // These pre-concat, so it ends up as persp * scale.
165 auto s2 = image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat,
166 SkSamplingOptions(), &persp)
167 ->makeWithLocalMatrix(scale);
168 draw(s2, false);
169
170 // 3. Providing pre-computed persp*scale to SkImage::makeShader()
171 auto s3 = image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat,
172 SkSamplingOptions(), &perspScale);
173 draw(s3, false);
174
175 // 4. Providing pre-computed persp*scale to makeWithLocalMatrix
176 auto s4 = image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, SkSamplingOptions())
177 ->makeWithLocalMatrix(perspScale);
178 draw(s4, false);
179 canvas->restore();
180
181 canvas->translate(0.f, 10.f + image->height()); // advance to next row
182
183 // SkGradientShader
184 const SkColor kGradColors[] = { SK_ColorBLACK, SK_ColorTRANSPARENT };
185 canvas->save();
186 // 1. scale provided to Make, drawn with persp
187 auto g1 = SkGradientShader::MakeRadial({imgRect.centerX(), imgRect.centerY()},
188 imgRect.width() / 2.f, kGradColors, nullptr, 2,
189 SkTileMode::kRepeat, 0, &scale);
190 draw(g1, true);
191
192 // 2. persp provided to Make, then wrapped with makeWithLocalMatrix (pre-concat as before).
193 auto g2 = SkGradientShader::MakeRadial({imgRect.centerX(), imgRect.centerY()},
194 imgRect.width() / 2.f, kGradColors, nullptr, 2,
195 SkTileMode::kRepeat, 0, &persp)
196 ->makeWithLocalMatrix(scale);
197 draw(g2, false);
198
199 // 3. Provide per-computed persp*scale to Make
200 auto g3 = SkGradientShader::MakeRadial({imgRect.centerX(), imgRect.centerY()},
201 imgRect.width() / 2.f, kGradColors, nullptr, 2,
202 SkTileMode::kRepeat, 0, &perspScale);
203 draw(g3, false);
204
205 // 4. Providing pre-computed persp*scale to makeWithLocalMatrix
206 auto g4 = SkGradientShader::MakeRadial({imgRect.centerX(), imgRect.centerY()},
207 imgRect.width() / 2.f, kGradColors, nullptr, 2,
208 SkTileMode::kRepeat)
209 ->makeWithLocalMatrix(perspScale);
210 draw(g4, false);
211 canvas->restore();
212 }
213