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