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