xref: /aosp_15_r20/external/skia/gm/gm.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2011 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 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBlendMode.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFont.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFontTypes.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSamplingOptions.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"  // IWYU pragma: keep
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTileMode.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTraceEvent.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ToolUtils.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "tools/fonts/FontToolUtils.h"
24*c8dee2aaSAndroid Build Coastguard Worker 
25*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GANESH)
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrRecordingContext.h"
27*c8dee2aaSAndroid Build Coastguard Worker #endif
28*c8dee2aaSAndroid Build Coastguard Worker 
29*c8dee2aaSAndroid Build Coastguard Worker #include <cstdarg>
30*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
31*c8dee2aaSAndroid Build Coastguard Worker 
32*c8dee2aaSAndroid Build Coastguard Worker using namespace skiagm;
33*c8dee2aaSAndroid Build Coastguard Worker 
34*c8dee2aaSAndroid Build Coastguard Worker static void draw_failure_message(SkCanvas* canvas, const char format[], ...) SK_PRINTF_LIKE(2, 3);
35*c8dee2aaSAndroid Build Coastguard Worker 
draw_failure_message(SkCanvas * canvas,const char format[],...)36*c8dee2aaSAndroid Build Coastguard Worker static void draw_failure_message(SkCanvas* canvas, const char format[], ...) {
37*c8dee2aaSAndroid Build Coastguard Worker     SkString failureMsg;
38*c8dee2aaSAndroid Build Coastguard Worker 
39*c8dee2aaSAndroid Build Coastguard Worker     va_list argp;
40*c8dee2aaSAndroid Build Coastguard Worker     va_start(argp, format);
41*c8dee2aaSAndroid Build Coastguard Worker     failureMsg.appendVAList(format, argp);
42*c8dee2aaSAndroid Build Coastguard Worker     va_end(argp);
43*c8dee2aaSAndroid Build Coastguard Worker 
44*c8dee2aaSAndroid Build Coastguard Worker     constexpr SkScalar kOffset = 5.0f;
45*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawColor(SkColorSetRGB(200,0,0));
46*c8dee2aaSAndroid Build Coastguard Worker     SkFont font = ToolUtils::DefaultPortableFont();
47*c8dee2aaSAndroid Build Coastguard Worker     SkRect bounds;
48*c8dee2aaSAndroid Build Coastguard Worker     font.measureText(failureMsg.c_str(), failureMsg.size(), SkTextEncoding::kUTF8, &bounds);
49*c8dee2aaSAndroid Build Coastguard Worker     SkPaint textPaint(SkColors::kWhite);
50*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawString(failureMsg, kOffset, bounds.height() + kOffset, font, textPaint);
51*c8dee2aaSAndroid Build Coastguard Worker }
52*c8dee2aaSAndroid Build Coastguard Worker 
draw_gpu_only_message(SkCanvas * canvas)53*c8dee2aaSAndroid Build Coastguard Worker static void draw_gpu_only_message(SkCanvas* canvas) {
54*c8dee2aaSAndroid Build Coastguard Worker     SkBitmap bmp;
55*c8dee2aaSAndroid Build Coastguard Worker     bmp.allocN32Pixels(128, 64);
56*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas bmpCanvas(bmp);
57*c8dee2aaSAndroid Build Coastguard Worker     bmpCanvas.drawColor(SK_ColorWHITE);
58*c8dee2aaSAndroid Build Coastguard Worker     SkFont  font(ToolUtils::DefaultPortableTypeface(), 20);
59*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint(SkColors::kRed);
60*c8dee2aaSAndroid Build Coastguard Worker     bmpCanvas.drawString("GPU Only", 20, 40, font, paint);
61*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix localM;
62*c8dee2aaSAndroid Build Coastguard Worker     localM.setRotate(35.f);
63*c8dee2aaSAndroid Build Coastguard Worker     localM.postTranslate(10.f, 0.f);
64*c8dee2aaSAndroid Build Coastguard Worker     paint.setShader(bmp.makeShader(SkTileMode::kMirror, SkTileMode::kMirror,
65*c8dee2aaSAndroid Build Coastguard Worker                                    SkSamplingOptions(SkFilterMode::kLinear,
66*c8dee2aaSAndroid Build Coastguard Worker                                                      SkMipmapMode::kNearest),
67*c8dee2aaSAndroid Build Coastguard Worker                                    localM));
68*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawPaint(paint);
69*c8dee2aaSAndroid Build Coastguard Worker }
70*c8dee2aaSAndroid Build Coastguard Worker 
handle_gm_failure(SkCanvas * canvas,DrawResult result,const SkString & errorMsg)71*c8dee2aaSAndroid Build Coastguard Worker static void handle_gm_failure(SkCanvas* canvas, DrawResult result, const SkString& errorMsg) {
72*c8dee2aaSAndroid Build Coastguard Worker     if (DrawResult::kFail == result) {
73*c8dee2aaSAndroid Build Coastguard Worker         draw_failure_message(canvas, "DRAW FAILED: %s", errorMsg.c_str());
74*c8dee2aaSAndroid Build Coastguard Worker     } else if (SkString(GM::kErrorMsg_DrawSkippedGpuOnly) == errorMsg) {
75*c8dee2aaSAndroid Build Coastguard Worker         draw_gpu_only_message(canvas);
76*c8dee2aaSAndroid Build Coastguard Worker     } else {
77*c8dee2aaSAndroid Build Coastguard Worker         draw_failure_message(canvas, "DRAW SKIPPED: %s", errorMsg.c_str());
78*c8dee2aaSAndroid Build Coastguard Worker     }
79*c8dee2aaSAndroid Build Coastguard Worker }
80*c8dee2aaSAndroid Build Coastguard Worker 
GM(SkColor bgColor)81*c8dee2aaSAndroid Build Coastguard Worker GM::GM(SkColor bgColor) {
82*c8dee2aaSAndroid Build Coastguard Worker     fMode = kGM_Mode;
83*c8dee2aaSAndroid Build Coastguard Worker     fBGColor = bgColor;
84*c8dee2aaSAndroid Build Coastguard Worker }
85*c8dee2aaSAndroid Build Coastguard Worker 
~GM()86*c8dee2aaSAndroid Build Coastguard Worker GM::~GM() {}
87*c8dee2aaSAndroid Build Coastguard Worker 
gpuSetup(SkCanvas * canvas,SkString * errorMsg,GraphiteTestContext * graphiteTestContext)88*c8dee2aaSAndroid Build Coastguard Worker DrawResult GM::gpuSetup(SkCanvas* canvas,
89*c8dee2aaSAndroid Build Coastguard Worker                         SkString* errorMsg,
90*c8dee2aaSAndroid Build Coastguard Worker                         GraphiteTestContext* graphiteTestContext) {
91*c8dee2aaSAndroid Build Coastguard Worker     TRACE_EVENT1("GM", TRACE_FUNC, "name", TRACE_STR_COPY(this->getName().c_str()));
92*c8dee2aaSAndroid Build Coastguard Worker     if (!fGpuSetup) {
93*c8dee2aaSAndroid Build Coastguard Worker         // When drawn in viewer, gpuSetup will be called multiple times with the same
94*c8dee2aaSAndroid Build Coastguard Worker         // GrContext or graphite::Context.
95*c8dee2aaSAndroid Build Coastguard Worker         fGpuSetup = true;
96*c8dee2aaSAndroid Build Coastguard Worker         fGpuSetupResult = this->onGpuSetup(canvas, errorMsg, graphiteTestContext);
97*c8dee2aaSAndroid Build Coastguard Worker     }
98*c8dee2aaSAndroid Build Coastguard Worker     if (fGpuSetupResult == DrawResult::kOk) {
99*c8dee2aaSAndroid Build Coastguard Worker         fGraphiteTestContext = graphiteTestContext;
100*c8dee2aaSAndroid Build Coastguard Worker     } else {
101*c8dee2aaSAndroid Build Coastguard Worker         handle_gm_failure(canvas, fGpuSetupResult, *errorMsg);
102*c8dee2aaSAndroid Build Coastguard Worker     }
103*c8dee2aaSAndroid Build Coastguard Worker 
104*c8dee2aaSAndroid Build Coastguard Worker     return fGpuSetupResult;
105*c8dee2aaSAndroid Build Coastguard Worker }
106*c8dee2aaSAndroid Build Coastguard Worker 
gpuTeardown()107*c8dee2aaSAndroid Build Coastguard Worker void GM::gpuTeardown() {
108*c8dee2aaSAndroid Build Coastguard Worker     this->onGpuTeardown();
109*c8dee2aaSAndroid Build Coastguard Worker 
110*c8dee2aaSAndroid Build Coastguard Worker     // After 'gpuTeardown' a GM can be reused with a different GrContext or graphite::Context. Reset
111*c8dee2aaSAndroid Build Coastguard Worker     // the flag so 'onGpuSetup' will be called.
112*c8dee2aaSAndroid Build Coastguard Worker     fGpuSetup = false;
113*c8dee2aaSAndroid Build Coastguard Worker     fGraphiteTestContext = nullptr;
114*c8dee2aaSAndroid Build Coastguard Worker }
115*c8dee2aaSAndroid Build Coastguard Worker 
draw(SkCanvas * canvas,SkString * errorMsg)116*c8dee2aaSAndroid Build Coastguard Worker DrawResult GM::draw(SkCanvas* canvas, SkString* errorMsg) {
117*c8dee2aaSAndroid Build Coastguard Worker     TRACE_EVENT1("GM", TRACE_FUNC, "name", TRACE_STR_COPY(this->getName().c_str()));
118*c8dee2aaSAndroid Build Coastguard Worker     this->drawBackground(canvas);
119*c8dee2aaSAndroid Build Coastguard Worker     return this->drawContent(canvas, errorMsg);
120*c8dee2aaSAndroid Build Coastguard Worker }
121*c8dee2aaSAndroid Build Coastguard Worker 
drawContent(SkCanvas * canvas,SkString * errorMsg)122*c8dee2aaSAndroid Build Coastguard Worker DrawResult GM::drawContent(SkCanvas* canvas, SkString* errorMsg) {
123*c8dee2aaSAndroid Build Coastguard Worker     TRACE_EVENT0("GM", TRACE_FUNC);
124*c8dee2aaSAndroid Build Coastguard Worker     this->onceBeforeDraw();
125*c8dee2aaSAndroid Build Coastguard Worker     SkAutoCanvasRestore acr(canvas, true);
126*c8dee2aaSAndroid Build Coastguard Worker     DrawResult drawResult = this->onDraw(canvas, errorMsg);
127*c8dee2aaSAndroid Build Coastguard Worker     if (DrawResult::kOk != drawResult) {
128*c8dee2aaSAndroid Build Coastguard Worker         handle_gm_failure(canvas, drawResult, *errorMsg);
129*c8dee2aaSAndroid Build Coastguard Worker     }
130*c8dee2aaSAndroid Build Coastguard Worker     return drawResult;
131*c8dee2aaSAndroid Build Coastguard Worker }
132*c8dee2aaSAndroid Build Coastguard Worker 
drawBackground(SkCanvas * canvas)133*c8dee2aaSAndroid Build Coastguard Worker void GM::drawBackground(SkCanvas* canvas) {
134*c8dee2aaSAndroid Build Coastguard Worker     TRACE_EVENT0("GM", TRACE_FUNC);
135*c8dee2aaSAndroid Build Coastguard Worker     this->onceBeforeDraw();
136*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawColor(fBGColor, SkBlendMode::kSrc);
137*c8dee2aaSAndroid Build Coastguard Worker }
138*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas,SkString * errorMsg)139*c8dee2aaSAndroid Build Coastguard Worker DrawResult GM::onDraw(SkCanvas* canvas, SkString* errorMsg) {
140*c8dee2aaSAndroid Build Coastguard Worker     this->onDraw(canvas);
141*c8dee2aaSAndroid Build Coastguard Worker     return DrawResult::kOk;
142*c8dee2aaSAndroid Build Coastguard Worker }
onDraw(SkCanvas *)143*c8dee2aaSAndroid Build Coastguard Worker void GM::onDraw(SkCanvas*) { SK_ABORT("Not implemented."); }
144*c8dee2aaSAndroid Build Coastguard Worker 
getISize()145*c8dee2aaSAndroid Build Coastguard Worker SkISize SimpleGM::getISize() { return fSize; }
getName() const146*c8dee2aaSAndroid Build Coastguard Worker SkString SimpleGM::getName() const { return fName; }
onDraw(SkCanvas * canvas,SkString * errorMsg)147*c8dee2aaSAndroid Build Coastguard Worker DrawResult SimpleGM::onDraw(SkCanvas* canvas, SkString* errorMsg) {
148*c8dee2aaSAndroid Build Coastguard Worker     return fDrawProc(canvas, errorMsg);
149*c8dee2aaSAndroid Build Coastguard Worker }
150*c8dee2aaSAndroid Build Coastguard Worker 
151*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GANESH)
getISize()152*c8dee2aaSAndroid Build Coastguard Worker SkISize SimpleGpuGM::getISize() { return fSize; }
getName() const153*c8dee2aaSAndroid Build Coastguard Worker SkString SimpleGpuGM::getName() const { return fName; }
onDraw(GrRecordingContext * rContext,SkCanvas * canvas,SkString * errorMsg)154*c8dee2aaSAndroid Build Coastguard Worker DrawResult SimpleGpuGM::onDraw(GrRecordingContext* rContext, SkCanvas* canvas, SkString* errorMsg) {
155*c8dee2aaSAndroid Build Coastguard Worker     return fDrawProc(rContext, canvas, errorMsg);
156*c8dee2aaSAndroid Build Coastguard Worker }
157*c8dee2aaSAndroid Build Coastguard Worker #endif
158*c8dee2aaSAndroid Build Coastguard Worker 
setBGColor(SkColor color)159*c8dee2aaSAndroid Build Coastguard Worker void GM::setBGColor(SkColor color) {
160*c8dee2aaSAndroid Build Coastguard Worker     fBGColor = color;
161*c8dee2aaSAndroid Build Coastguard Worker }
162*c8dee2aaSAndroid Build Coastguard Worker 
animate(double nanos)163*c8dee2aaSAndroid Build Coastguard Worker bool GM::animate(double nanos) { return this->onAnimate(nanos); }
164*c8dee2aaSAndroid Build Coastguard Worker 
runAsBench() const165*c8dee2aaSAndroid Build Coastguard Worker bool GM::runAsBench() const { return false; }
166*c8dee2aaSAndroid Build Coastguard Worker 
onOnceBeforeDraw()167*c8dee2aaSAndroid Build Coastguard Worker void GM::onOnceBeforeDraw() {}
168*c8dee2aaSAndroid Build Coastguard Worker 
onAnimate(double)169*c8dee2aaSAndroid Build Coastguard Worker bool GM::onAnimate(double /*nanos*/) { return false; }
170*c8dee2aaSAndroid Build Coastguard Worker 
onChar(SkUnichar uni)171*c8dee2aaSAndroid Build Coastguard Worker bool GM::onChar(SkUnichar uni) { return false; }
172*c8dee2aaSAndroid Build Coastguard Worker 
onGetControls(SkMetaData *)173*c8dee2aaSAndroid Build Coastguard Worker bool GM::onGetControls(SkMetaData*) { return false; }
174*c8dee2aaSAndroid Build Coastguard Worker 
onSetControls(const SkMetaData &)175*c8dee2aaSAndroid Build Coastguard Worker void GM::onSetControls(const SkMetaData&) {}
176*c8dee2aaSAndroid Build Coastguard Worker 
177*c8dee2aaSAndroid Build Coastguard Worker /////////////////////////////////////////////////////////////////////////////////////////////
178*c8dee2aaSAndroid Build Coastguard Worker 
drawSizeBounds(SkCanvas * canvas,SkColor color)179*c8dee2aaSAndroid Build Coastguard Worker void GM::drawSizeBounds(SkCanvas* canvas, SkColor color) {
180*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawRect(SkRect::Make(this->getISize()), SkPaint(SkColor4f::FromColor(color)));
181*c8dee2aaSAndroid Build Coastguard Worker }
182*c8dee2aaSAndroid Build Coastguard Worker 
183*c8dee2aaSAndroid Build Coastguard Worker // need to explicitly declare this, or we get some weird infinite loop llist
184*c8dee2aaSAndroid Build Coastguard Worker template GMRegistry* GMRegistry::gHead;
185*c8dee2aaSAndroid Build Coastguard Worker 
186*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GANESH)
onDraw(GrRecordingContext * rContext,SkCanvas * canvas,SkString * errorMsg)187*c8dee2aaSAndroid Build Coastguard Worker DrawResult GpuGM::onDraw(GrRecordingContext* rContext, SkCanvas* canvas, SkString* errorMsg) {
188*c8dee2aaSAndroid Build Coastguard Worker     this->onDraw(rContext, canvas);
189*c8dee2aaSAndroid Build Coastguard Worker     return DrawResult::kOk;
190*c8dee2aaSAndroid Build Coastguard Worker }
onDraw(GrRecordingContext *,SkCanvas *)191*c8dee2aaSAndroid Build Coastguard Worker void GpuGM::onDraw(GrRecordingContext*, SkCanvas*) {
192*c8dee2aaSAndroid Build Coastguard Worker     SK_ABORT("Not implemented.");
193*c8dee2aaSAndroid Build Coastguard Worker }
194*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas,SkString * errorMsg)195*c8dee2aaSAndroid Build Coastguard Worker DrawResult GpuGM::onDraw(SkCanvas* canvas, SkString* errorMsg) {
196*c8dee2aaSAndroid Build Coastguard Worker 
197*c8dee2aaSAndroid Build Coastguard Worker     auto rContext = canvas->recordingContext();
198*c8dee2aaSAndroid Build Coastguard Worker     if (!rContext) {
199*c8dee2aaSAndroid Build Coastguard Worker         *errorMsg = kErrorMsg_DrawSkippedGpuOnly;
200*c8dee2aaSAndroid Build Coastguard Worker         return DrawResult::kSkip;
201*c8dee2aaSAndroid Build Coastguard Worker     }
202*c8dee2aaSAndroid Build Coastguard Worker     if (rContext->abandoned()) {
203*c8dee2aaSAndroid Build Coastguard Worker         *errorMsg = "GrContext abandoned.";
204*c8dee2aaSAndroid Build Coastguard Worker         return DrawResult::kSkip;
205*c8dee2aaSAndroid Build Coastguard Worker     }
206*c8dee2aaSAndroid Build Coastguard Worker     return this->onDraw(rContext, canvas, errorMsg);
207*c8dee2aaSAndroid Build Coastguard Worker }
208*c8dee2aaSAndroid Build Coastguard Worker #endif
209*c8dee2aaSAndroid Build Coastguard Worker 
210*c8dee2aaSAndroid Build Coastguard Worker template <typename Fn>
mark(SkCanvas * canvas,SkScalar x,SkScalar y,Fn && fn)211*c8dee2aaSAndroid Build Coastguard Worker static void mark(SkCanvas* canvas, SkScalar x, SkScalar y, Fn&& fn) {
212*c8dee2aaSAndroid Build Coastguard Worker     SkPaint alpha;
213*c8dee2aaSAndroid Build Coastguard Worker     alpha.setAlpha(0x50);
214*c8dee2aaSAndroid Build Coastguard Worker     canvas->saveLayer(nullptr, &alpha);
215*c8dee2aaSAndroid Build Coastguard Worker         canvas->translate(x,y);
216*c8dee2aaSAndroid Build Coastguard Worker         canvas->scale(2,2);
217*c8dee2aaSAndroid Build Coastguard Worker         fn();
218*c8dee2aaSAndroid Build Coastguard Worker     canvas->restore();
219*c8dee2aaSAndroid Build Coastguard Worker }
220*c8dee2aaSAndroid Build Coastguard Worker 
MarkGMGood(SkCanvas * canvas,SkScalar x,SkScalar y)221*c8dee2aaSAndroid Build Coastguard Worker void MarkGMGood(SkCanvas* canvas, SkScalar x, SkScalar y) {
222*c8dee2aaSAndroid Build Coastguard Worker     mark(canvas, x,y, [&]{
223*c8dee2aaSAndroid Build Coastguard Worker         // A green circle.
224*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawCircle(0, 0, 12, SkPaint(SkColor4f::FromColor(SkColorSetRGB(27, 158, 119))));
225*c8dee2aaSAndroid Build Coastguard Worker 
226*c8dee2aaSAndroid Build Coastguard Worker         // Cut out a check mark.
227*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint(SkColors::kTransparent);
228*c8dee2aaSAndroid Build Coastguard Worker         paint.setBlendMode(SkBlendMode::kSrc);
229*c8dee2aaSAndroid Build Coastguard Worker         paint.setStrokeWidth(2);
230*c8dee2aaSAndroid Build Coastguard Worker         paint.setStyle(SkPaint::kStroke_Style);
231*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawLine(-6, 0,
232*c8dee2aaSAndroid Build Coastguard Worker                          -1, 5, paint);
233*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawLine(-1, +5,
234*c8dee2aaSAndroid Build Coastguard Worker                          +7, -5, paint);
235*c8dee2aaSAndroid Build Coastguard Worker     });
236*c8dee2aaSAndroid Build Coastguard Worker }
237*c8dee2aaSAndroid Build Coastguard Worker 
MarkGMBad(SkCanvas * canvas,SkScalar x,SkScalar y)238*c8dee2aaSAndroid Build Coastguard Worker void MarkGMBad(SkCanvas* canvas, SkScalar x, SkScalar y) {
239*c8dee2aaSAndroid Build Coastguard Worker     mark(canvas, x,y, [&] {
240*c8dee2aaSAndroid Build Coastguard Worker         // A red circle.
241*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawCircle(0,0, 12, SkPaint(SkColor4f::FromColor(SkColorSetRGB(231, 41, 138))));
242*c8dee2aaSAndroid Build Coastguard Worker 
243*c8dee2aaSAndroid Build Coastguard Worker         // Cut out an 'X'.
244*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint(SkColors::kTransparent);
245*c8dee2aaSAndroid Build Coastguard Worker         paint.setBlendMode(SkBlendMode::kSrc);
246*c8dee2aaSAndroid Build Coastguard Worker         paint.setStrokeWidth(2);
247*c8dee2aaSAndroid Build Coastguard Worker         paint.setStyle(SkPaint::kStroke_Style);
248*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawLine(-5,-5,
249*c8dee2aaSAndroid Build Coastguard Worker                          +5,+5, paint);
250*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawLine(+5,-5,
251*c8dee2aaSAndroid Build Coastguard Worker                          -5,+5, paint);
252*c8dee2aaSAndroid Build Coastguard Worker     });
253*c8dee2aaSAndroid Build Coastguard Worker }
254*c8dee2aaSAndroid Build Coastguard Worker 
255*c8dee2aaSAndroid Build Coastguard Worker namespace skiagm {
Register(skiagm::GM * gm)256*c8dee2aaSAndroid Build Coastguard Worker void Register(skiagm::GM* gm) {
257*c8dee2aaSAndroid Build Coastguard Worker     // The skiagm::GMRegistry class is a subclass of sk_tools::Registry. Instances of
258*c8dee2aaSAndroid Build Coastguard Worker     // sk_tools::Registry form a linked list (there is one such list for each subclass), where each
259*c8dee2aaSAndroid Build Coastguard Worker     // instance holds a value and a pointer to the next sk_tools::Registry instance. The head of
260*c8dee2aaSAndroid Build Coastguard Worker     // this linked list is stored in a global variable. The sk_tools::Registry constructor
261*c8dee2aaSAndroid Build Coastguard Worker     // automatically pushes a new instance to the head of said linked list. Therefore, in order to
262*c8dee2aaSAndroid Build Coastguard Worker     // register a value in the GM registry, it suffices to just instantiate skiagm::GMRegistry with
263*c8dee2aaSAndroid Build Coastguard Worker     // the value we wish to register.
264*c8dee2aaSAndroid Build Coastguard Worker     new skiagm::GMRegistry([=]() { return std::unique_ptr<skiagm::GM>(gm); });
265*c8dee2aaSAndroid Build Coastguard Worker }
266*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skiagm
267