1 /*
2  * Copyright 2011 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 #include "SkCanvas.h"
10 #include "SkGradientShader.h"
11 #include "SkPath.h"
12 
13 namespace skiagm {
14 
makebm(SkBitmap * bm,int w,int h)15 static void makebm(SkBitmap* bm, int w, int h) {
16     bm->allocN32Pixels(w, h);
17     bm->eraseColor(SK_ColorTRANSPARENT);
18 
19     SkCanvas    canvas(*bm);
20     SkScalar    s = SkIntToScalar(SkMin32(w, h));
21     SkPoint     pts[] = { { 0, 0 }, { s, s } };
22     SkColor     colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
23     SkScalar    pos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
24     SkPaint     paint;
25 
26     paint.setDither(true);
27     paint.setShader(SkGradientShader::CreateLinear(pts, colors, pos,
28                 SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode))->unref();
29     canvas.drawPaint(paint);
30 }
31 
32 ///////////////////////////////////////////////////////////////////////////////
33 
34 struct GradData {
35     int             fCount;
36     const SkColor*  fColors;
37     const SkScalar* fPos;
38 };
39 
40 static const SkColor gColors[] = {
41     SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
42 };
43 
44 static const GradData gGradData[] = {
45     { 2, gColors, nullptr },
46     { 5, gColors, nullptr },
47 };
48 
MakeLinear(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm)49 static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
50     return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos, data.fCount, tm);
51 }
52 
MakeRadial(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm)53 static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
54     SkPoint center;
55     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
56                SkScalarAve(pts[0].fY, pts[1].fY));
57     return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
58                                           data.fPos, data.fCount, tm);
59 }
60 
MakeSweep(const SkPoint pts[2],const GradData & data,SkShader::TileMode)61 static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data, SkShader::TileMode) {
62     SkPoint center;
63     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
64                SkScalarAve(pts[0].fY, pts[1].fY));
65     return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors, data.fPos, data.fCount);
66 }
67 
Make2Conical(const SkPoint pts[2],const GradData & data,SkShader::TileMode tm)68 static SkShader* Make2Conical(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
69     SkPoint center0, center1;
70     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
71                 SkScalarAve(pts[0].fY, pts[1].fY));
72     center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
73                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
74     return SkGradientShader::CreateTwoPointConical(
75                             center1, (pts[1].fX - pts[0].fX) / 7,
76                             center0, (pts[1].fX - pts[0].fX) / 2,
77                             data.fColors, data.fPos, data.fCount, tm);
78 }
79 
80 typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm);
81 
82 static const GradMaker gGradMakers[] = {
83     MakeLinear, MakeRadial, MakeSweep, Make2Conical
84 };
85 
86 ///////////////////////////////////////////////////////////////////////////////
87 
88 class ShaderTextGM : public GM {
89 public:
ShaderTextGM()90     ShaderTextGM() {
91         this->setBGColor(sk_tool_utils::color_to_565(0xFFDDDDDD));
92     }
93 
94 protected:
95 
onShortName()96     SkString onShortName() override {
97         return SkString("shadertext");
98     }
99 
onISize()100     SkISize onISize() override { return SkISize::Make(1450, 500); }
101 
onDraw(SkCanvas * canvas)102     void onDraw(SkCanvas* canvas) override {
103         const char text[] = "Shaded Text";
104         const int textLen = SK_ARRAY_COUNT(text) - 1;
105         const int pointSize = 36;
106 
107         const int w = pointSize * textLen;
108         const int h = pointSize;
109 
110         SkPoint pts[2] = {
111             { 0, 0 },
112             { SkIntToScalar(w), SkIntToScalar(h) }
113         };
114         SkScalar textBase = SkIntToScalar(h/2);
115 
116         SkShader::TileMode tileModes[] = {
117             SkShader::kClamp_TileMode,
118             SkShader::kRepeat_TileMode,
119             SkShader::kMirror_TileMode
120         };
121 
122         static const int gradCount = SK_ARRAY_COUNT(gGradData) *
123                                      SK_ARRAY_COUNT(gGradMakers);
124         static const int bmpCount = SK_ARRAY_COUNT(tileModes) *
125                                     SK_ARRAY_COUNT(tileModes);
126         SkShader* shaders[gradCount + bmpCount];
127 
128         int shdIdx = 0;
129         for (size_t d = 0; d < SK_ARRAY_COUNT(gGradData); ++d) {
130             for (size_t m = 0; m < SK_ARRAY_COUNT(gGradMakers); ++m) {
131                 shaders[shdIdx++] = gGradMakers[m](pts,
132                                                    gGradData[d],
133                                                    SkShader::kClamp_TileMode);
134             }
135         }
136 
137         SkBitmap bm;
138         makebm(&bm, w/16, h/4);
139         for (size_t tx = 0; tx < SK_ARRAY_COUNT(tileModes); ++tx) {
140             for (size_t ty = 0; ty < SK_ARRAY_COUNT(tileModes); ++ty) {
141                 shaders[shdIdx++] = SkShader::CreateBitmapShader(bm, tileModes[tx], tileModes[ty]);
142             }
143         }
144 
145         SkPaint paint;
146         paint.setDither(true);
147         paint.setAntiAlias(true);
148         sk_tool_utils::set_portable_typeface(&paint);
149         paint.setTextSize(SkIntToScalar(pointSize));
150 
151         canvas->save();
152         canvas->translate(SkIntToScalar(20), SkIntToScalar(10));
153 
154         SkPath path;
155         path.arcTo(SkRect::MakeXYWH(SkIntToScalar(-40), SkIntToScalar(15),
156                                     SkIntToScalar(300), SkIntToScalar(90)),
157                                     SkIntToScalar(225), SkIntToScalar(90),
158                                     false);
159         path.close();
160 
161         static const int testsPerCol = 8;
162         static const int rowHeight = 60;
163         static const int colWidth = 300;
164         canvas->save();
165         for (int s = 0; s < static_cast<int>(SK_ARRAY_COUNT(shaders)); s++) {
166             canvas->save();
167             int i = 2*s;
168             canvas->translate(SkIntToScalar((i / testsPerCol) * colWidth),
169                               SkIntToScalar((i % testsPerCol) * rowHeight));
170             paint.setShader(shaders[s])->unref();
171             canvas->drawText(text, textLen, 0, textBase, paint);
172             canvas->restore();
173             canvas->save();
174             ++i;
175             canvas->translate(SkIntToScalar((i / testsPerCol) * colWidth),
176                               SkIntToScalar((i % testsPerCol) * rowHeight));
177             canvas->drawTextOnPath(text, textLen, path, nullptr, paint);
178             canvas->restore();
179         }
180         canvas->restore();
181 
182     }
183 
184 private:
185     typedef GM INHERITED;
186 };
187 
188 ///////////////////////////////////////////////////////////////////////////////
189 
MyFactory(void *)190 static GM* MyFactory(void*) { return new ShaderTextGM; }
191 static GMRegistry reg(MyFactory);
192 }
193