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