• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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