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.h"
9 
10 #include "GrClip.h"
11 #include "GrContext.h"
12 #include "GrRenderTargetContext.h"
13 #include "GrSurfaceContextPriv.h"
14 #include "SkGr.h"
15 #include "SkGradientShader.h"
16 
17 static constexpr SkScalar kTileWidth = 40;
18 static constexpr SkScalar kTileHeight = 30;
19 
20 static constexpr int kRowCount = 4;
21 static constexpr int kColCount = 3;
22 
draw_text(SkCanvas * canvas,const char * text)23 static void draw_text(SkCanvas* canvas, const char* text) {
24     canvas->drawString(text, 0, 0, SkFont(nullptr, 12), SkPaint());
25 }
26 
draw_gradient_tiles(SkCanvas * canvas,bool alignGradients)27 static void draw_gradient_tiles(SkCanvas* canvas, bool alignGradients) {
28     // Always draw the same gradient
29     static constexpr SkPoint pts[] = { {0.f, 0.f}, {0.25f * kTileWidth, 0.25f * kTileHeight} };
30     static constexpr SkColor colors[] = { SK_ColorBLUE, SK_ColorWHITE };
31 
32     GrRenderTargetContext* rtc = canvas->internal_private_accessTopLayerRenderTargetContext();
33 
34     auto gradient = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kMirror_TileMode);
35     SkPaint paint;
36     paint.setShader(gradient);
37 
38     for (int i = 0; i < kRowCount; ++i) {
39         for (int j = 0; j < kColCount; ++j) {
40             SkRect tile = SkRect::MakeWH(kTileWidth, kTileHeight);
41             if (alignGradients) {
42                 tile.offset(j * kTileWidth, i * kTileHeight);
43             } else {
44                 canvas->save();
45                 canvas->translate(j * kTileWidth, i * kTileHeight);
46             }
47 
48             unsigned aa = SkCanvas::kNone_QuadAAFlags;
49             if (i == 0) {
50                 aa |= SkCanvas::kTop_QuadAAFlag;
51             }
52             if (i == kRowCount - 1) {
53                 aa |= SkCanvas::kBottom_QuadAAFlag;
54             }
55             if (j == 0) {
56                 aa |= SkCanvas::kLeft_QuadAAFlag;
57             }
58             if (j == kColCount - 1) {
59                 aa |= SkCanvas::kRight_QuadAAFlag;
60             }
61 
62             if (rtc) {
63                 // Use non-public API to leverage general GrPaint capabilities
64                 SkMatrix view = canvas->getTotalMatrix();
65                 GrPaint grPaint;
66                 SkPaintToGrPaint(rtc->surfPriv().getContext(), rtc->colorSpaceInfo(), paint, view,
67                                  &grPaint);
68                 rtc->fillRectWithEdgeAA(GrNoClip(), std::move(grPaint),
69                                         static_cast<GrQuadAAFlags>(aa), view, tile);
70             } else {
71                 // Fallback to solid color on raster backend since the public API only has color
72                 SkColor color = alignGradients ? SK_ColorBLUE
73                                                : (i * kColCount + j) % 2 == 0 ? SK_ColorBLUE
74                                                                               : SK_ColorWHITE;
75                 canvas->experimental_DrawEdgeAARectV1(
76                         tile, static_cast<SkCanvas::QuadAAFlags>(aa), color, SkBlendMode::kSrcOver);
77             }
78 
79             if (!alignGradients) {
80                 // Pop off the matrix translation when drawing unaligned
81                 canvas->restore();
82             }
83         }
84     }
85 }
86 
draw_color_tiles(SkCanvas * canvas,bool multicolor)87 static void draw_color_tiles(SkCanvas* canvas, bool multicolor) {
88     for (int i = 0; i < kRowCount; ++i) {
89         for (int j = 0; j < kColCount; ++j) {
90             SkRect tile = SkRect::MakeXYWH(j * kTileWidth, i * kTileHeight, kTileWidth, kTileHeight);
91 
92             SkColor4f color;
93             if (multicolor) {
94                 color = {(i + 1.f) / kRowCount, (j + 1.f) / kColCount, .4f, 1.f};
95             } else {
96                 color = {.2f, .8f, .3f, 1.f};
97             }
98 
99             unsigned aa = SkCanvas::kNone_QuadAAFlags;
100             if (i == 0) {
101                 aa |= SkCanvas::kTop_QuadAAFlag;
102             }
103             if (i == kRowCount - 1) {
104                 aa |= SkCanvas::kBottom_QuadAAFlag;
105             }
106             if (j == 0) {
107                 aa |= SkCanvas::kLeft_QuadAAFlag;
108             }
109             if (j == kColCount - 1) {
110                 aa |= SkCanvas::kRight_QuadAAFlag;
111             }
112 
113             canvas->experimental_DrawEdgeAARectV1(
114                     tile, static_cast<SkCanvas::QuadAAFlags>(aa), color.toSkColor(),
115                     SkBlendMode::kSrcOver);
116         }
117     }
118 }
119 
draw_tile_boundaries(SkCanvas * canvas,const SkMatrix & local)120 static void draw_tile_boundaries(SkCanvas* canvas, const SkMatrix& local) {
121     // Draw grid of red lines at interior tile boundaries.
122     static constexpr SkScalar kLineOutset = 10.f;
123     SkPaint paint;
124     paint.setAntiAlias(true);
125     paint.setColor(SK_ColorRED);
126     paint.setStyle(SkPaint::kStroke_Style);
127     paint.setStrokeWidth(0.f);
128     for (int x = 1; x < kColCount; ++x) {
129         SkPoint pts[] = {{x * kTileWidth, 0}, {x * kTileWidth, kRowCount * kTileHeight}};
130         local.mapPoints(pts, 2);
131         SkVector v = pts[1] - pts[0];
132         v.setLength(v.length() + kLineOutset);
133         canvas->drawLine(pts[1] - v, pts[0] + v, paint);
134     }
135     for (int y = 1; y < kRowCount; ++y) {
136         SkPoint pts[] = {{0, y * kTileHeight}, {kTileWidth * kColCount, y * kTileHeight}};
137         local.mapPoints(pts, 2);
138         SkVector v = pts[1] - pts[0];
139         v.setLength(v.length() + kLineOutset);
140         canvas->drawLine(pts[1] - v, pts[0] + v, paint);
141     }
142 }
143 
144 // Tile renderers (column variation)
145 typedef void (*TileRenderer)(SkCanvas*);
146 static TileRenderer kTileSets[] = {
__anon943b19380102() 147     [](SkCanvas* canvas) { draw_gradient_tiles(canvas, /* aligned */ false); },
__anon943b19380202() 148     [](SkCanvas* canvas) { draw_gradient_tiles(canvas, /* aligned */ true); },
__anon943b19380302() 149     [](SkCanvas* canvas) { draw_color_tiles(canvas, /* multicolor */ false); },
__anon943b19380402() 150     [](SkCanvas* canvas) { draw_color_tiles(canvas, /* multicolor */true); },
151 };
152 static const char* kTileSetNames[] = { "Local", "Aligned", "Green", "Multicolor" };
153 static_assert(SK_ARRAY_COUNT(kTileSets) == SK_ARRAY_COUNT(kTileSetNames), "Count mismatch");
154 
155 namespace skiagm {
156 
157 class DrawQuadSetGM : public GM {
158 private:
onShortName()159     SkString onShortName() final { return SkString("draw_quad_set"); }
onISize()160     SkISize onISize() override { return SkISize::Make(800, 800); }
161 
onDraw(SkCanvas * canvas)162     void onDraw(SkCanvas* canvas) override {
163         SkMatrix rowMatrices[5];
164         // Identity
165         rowMatrices[0].setIdentity();
166         // Translate/scale
167         rowMatrices[1].setTranslate(5.5f, 20.25f);
168         rowMatrices[1].postScale(.9f, .7f);
169         // Rotation
170         rowMatrices[2].setRotate(20.0f);
171         rowMatrices[2].preTranslate(15.f, -20.f);
172         // Skew
173         rowMatrices[3].setSkew(.5f, .25f);
174         rowMatrices[3].preTranslate(-30.f, 0.f);
175         // Perspective
176         SkPoint src[4];
177         SkRect::MakeWH(kColCount * kTileWidth, kRowCount * kTileHeight).toQuad(src);
178         SkPoint dst[4] = {{0, 0},
179                           {kColCount * kTileWidth + 10.f, 15.f},
180                           {kColCount * kTileWidth - 28.f, kRowCount * kTileHeight + 40.f},
181                           {25.f, kRowCount * kTileHeight - 15.f}};
182         SkAssertResult(rowMatrices[4].setPolyToPoly(src, dst, 4));
183         rowMatrices[4].preTranslate(0.f, +10.f);
184         static const char* matrixNames[] = { "Identity", "T+S", "Rotate", "Skew", "Perspective" };
185         static_assert(SK_ARRAY_COUNT(matrixNames) == SK_ARRAY_COUNT(rowMatrices), "Count mismatch");
186 
187         // Print a column header
188         canvas->save();
189         canvas->translate(110.f, 20.f);
190         for (size_t j = 0; j < SK_ARRAY_COUNT(kTileSetNames); ++j) {
191             draw_text(canvas, kTileSetNames[j]);
192             canvas->translate(kColCount * kTileWidth + 30.f, 0.f);
193         }
194         canvas->restore();
195         canvas->translate(0.f, 40.f);
196 
197         // Render all tile variations
198         for (size_t i = 0; i < SK_ARRAY_COUNT(rowMatrices); ++i) {
199             canvas->save();
200             canvas->translate(10.f, 0.5f * kRowCount * kTileHeight);
201             draw_text(canvas, matrixNames[i]);
202 
203             canvas->translate(100.f, -0.5f * kRowCount * kTileHeight);
204             for (size_t j = 0; j < SK_ARRAY_COUNT(kTileSets); ++j) {
205                 canvas->save();
206                 draw_tile_boundaries(canvas, rowMatrices[i]);
207 
208                 canvas->concat(rowMatrices[i]);
209                 kTileSets[j](canvas);
210                 // Undo the local transformation
211                 canvas->restore();
212                 // And advance to the next column
213                 canvas->translate(kColCount * kTileWidth + 30.f, 0.f);
214             }
215             // Reset back to the left edge
216             canvas->restore();
217             // And advance to the next row
218             canvas->translate(0.f, kRowCount * kTileHeight + 20.f);
219         }
220     }
221 };
222 
223 DEF_GM(return new DrawQuadSetGM();)
224 
225 } // namespace skiagm
226