1 /*
2  * Copyright 2015 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 // This test only works with the GPU backend.
9 
10 #include "gm.h"
11 #include "sk_tool_utils.h"
12 
13 #include "GrContext.h"
14 #include "GrRenderTargetContextPriv.h"
15 #include "SkGr.h"
16 #include "SkGradientShader.h"
17 #include "effects/GrConstColorProcessor.h"
18 #include "ops/GrDrawOp.h"
19 #include "ops/GrFillRectOp.h"
20 
21 namespace skiagm {
22 /**
23  * This GM directly exercises GrConstColorProcessor.
24  */
25 class ConstColorProcessor : public GpuGM {
26 public:
ConstColorProcessor()27     ConstColorProcessor() {
28         this->setBGColor(0xFFDDDDDD);
29     }
30 
31 protected:
onShortName()32     SkString onShortName() override {
33         return SkString("const_color_processor");
34     }
35 
onISize()36     SkISize onISize() override {
37         return SkISize::Make(kWidth, kHeight);
38     }
39 
onOnceBeforeDraw()40     void onOnceBeforeDraw() override {
41         SkColor colors[] = { 0xFFFF0000, 0x2000FF00, 0xFF0000FF};
42         SkPoint pts[] = { SkPoint::Make(0, 0), SkPoint::Make(kRectSize, kRectSize) };
43         fShader = SkGradientShader::MakeLinear(pts, colors, nullptr, SK_ARRAY_COUNT(colors),
44                                                SkShader::kClamp_TileMode);
45     }
46 
onDraw(GrContext * context,GrRenderTargetContext * renderTargetContext,SkCanvas * canvas)47     void onDraw(GrContext* context, GrRenderTargetContext* renderTargetContext,
48                 SkCanvas* canvas) override {
49         constexpr GrColor kColors[] = {
50             0xFFFFFFFF,
51             0xFFFF00FF,
52             0x80000000,
53             0x00000000,
54         };
55 
56         constexpr SkColor kPaintColors[] = {
57             0xFFFFFFFF,
58             0xFFFF0000,
59             0x80FF0000,
60             0x00000000,
61         };
62 
63         const char* kModeStrs[] {
64             "kIgnore",
65             "kModulateRGBA",
66             "kModulateA",
67         };
68         GR_STATIC_ASSERT(SK_ARRAY_COUNT(kModeStrs) == GrConstColorProcessor::kInputModeCnt);
69 
70         SkScalar y = kPad;
71         SkScalar x = kPad;
72         SkScalar maxW = 0;
73         for (size_t paintType = 0; paintType < SK_ARRAY_COUNT(kPaintColors) + 1; ++paintType) {
74             for (size_t procColor = 0; procColor < SK_ARRAY_COUNT(kColors); ++procColor) {
75                 for (int m = 0; m < GrConstColorProcessor::kInputModeCnt; ++m) {
76                     // translate by x,y for the canvas draws and the test target draws.
77                     canvas->save();
78                     canvas->translate(x, y);
79                     const SkMatrix viewMatrix = SkMatrix::MakeTrans(x, y);
80 
81                     // rect to draw
82                     SkRect renderRect = SkRect::MakeXYWH(0, 0, kRectSize, kRectSize);
83 
84                     GrPaint grPaint;
85                     SkPaint skPaint;
86                     if (paintType >= SK_ARRAY_COUNT(kPaintColors)) {
87                         skPaint.setShader(fShader);
88                     } else {
89                         skPaint.setColor(kPaintColors[paintType]);
90                     }
91                     SkAssertResult(SkPaintToGrPaint(context, renderTargetContext->colorSpaceInfo(),
92                                                     skPaint, viewMatrix, &grPaint));
93 
94                     GrConstColorProcessor::InputMode mode = (GrConstColorProcessor::InputMode) m;
95                     SkPMColor4f color = SkPMColor4f::FromBytes_RGBA(kColors[procColor]);
96                     auto fp = GrConstColorProcessor::Make(color, mode);
97 
98                     grPaint.addColorFragmentProcessor(std::move(fp));
99                     renderTargetContext->priv().testingOnly_addDrawOp(
100                             GrFillRectOp::Make(context, std::move(grPaint), GrAAType::kNone,
101                                                viewMatrix, renderRect));
102 
103                     // Draw labels for the input to the processor and the processor to the right of
104                     // the test rect. The input label appears above the processor label.
105                     SkFont labelFont;
106                     labelFont.setTypeface(sk_tool_utils::create_portable_typeface());
107                     labelFont.setEdging(SkFont::Edging::kAntiAlias);
108                     labelFont.setSize(10.f);
109                     SkPaint labelPaint;
110                     labelPaint.setAntiAlias(true);
111                     SkString inputLabel;
112                     inputLabel.set("Input: ");
113                     if (paintType >= SK_ARRAY_COUNT(kPaintColors)) {
114                         inputLabel.append("gradient");
115                     } else {
116                         inputLabel.appendf("0x%08x", kPaintColors[paintType]);
117                     }
118                     SkString procLabel;
119                     procLabel.printf("Proc: [0x%08x, %s]", kColors[procColor], kModeStrs[m]);
120 
121                     SkRect inputLabelBounds;
122                     // get the bounds of the text in order to position it
123                     labelFont.measureText(inputLabel.c_str(), inputLabel.size(),
124                                           kUTF8_SkTextEncoding, &inputLabelBounds);
125                     canvas->drawString(inputLabel, renderRect.fRight + kPad, -inputLabelBounds.fTop,
126                                        labelFont, labelPaint);
127                     // update the bounds to reflect the offset we used to draw it.
128                     inputLabelBounds.offset(renderRect.fRight + kPad, -inputLabelBounds.fTop);
129 
130                     SkRect procLabelBounds;
131                     labelFont.measureText(procLabel.c_str(), procLabel.size(),
132                                           kUTF8_SkTextEncoding, &procLabelBounds);
133                     canvas->drawString(procLabel, renderRect.fRight + kPad,
134                                        inputLabelBounds.fBottom + 2.f - procLabelBounds.fTop,
135                                        labelFont, labelPaint);
136                     procLabelBounds.offset(renderRect.fRight + kPad,
137                                            inputLabelBounds.fBottom + 2.f - procLabelBounds.fTop);
138 
139                     labelPaint.setStrokeWidth(0);
140                     labelPaint.setStyle(SkPaint::kStroke_Style);
141                     canvas->drawRect(renderRect, labelPaint);
142 
143                     canvas->restore();
144 
145                     // update x and y for the next test case.
146                     SkScalar height = renderRect.height();
147                     SkScalar width = SkTMax(inputLabelBounds.fRight, procLabelBounds.fRight);
148                     maxW = SkTMax(maxW, width);
149                     y += height + kPad;
150                     if (y + height > kHeight) {
151                         y = kPad;
152                         x += maxW + kPad;
153                         maxW = 0;
154                     }
155                 }
156             }
157         }
158     }
159 
160 private:
161     // Use this as a way of generating and input FP
162     sk_sp<SkShader> fShader;
163 
164     static constexpr SkScalar       kPad = 10.f;
165     static constexpr SkScalar       kRectSize = 20.f;
166     static constexpr int            kWidth  = 820;
167     static constexpr int            kHeight = 500;
168 
169     typedef GM INHERITED;
170 };
171 
172 DEF_GM(return new ConstColorProcessor;)
173 }
174