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#include "SampleCode.h"
8#include "SkBlurMask.h"
9#include "SkCanvas.h"
10#include "SkView.h"
11#include "Sk1DPathEffect.h"
12#include "Sk2DPathEffect.h"
13#include "SkBlurMaskFilter.h"
14#include "SkColorMatrixFilter.h"
15#include "SkColorPriv.h"
16#include "SkCornerPathEffect.h"
17#include "SkDashPathEffect.h"
18#include "SkDiscretePathEffect.h"
19#include "SkEmbossMaskFilter.h"
20#include "SkReadBuffer.h"
21#include "SkWriteBuffer.h"
22#include "SkGradientShader.h"
23#include "SkMath.h"
24#include "SkPath.h"
25#include "SkPictureRecorder.h"
26#include "SkRegion.h"
27#include "SkShader.h"
28#include "SkCornerPathEffect.h"
29#include "SkPathMeasure.h"
30#include "SkPicture.h"
31#include "SkRandom.h"
32#include "SkTypeface.h"
33#include "SkUtils.h"
34
35#include <math.h>
36#include "DecodeFile.h"
37
38class Dot2DPathEffect : public Sk2DPathEffect {
39public:
40    Dot2DPathEffect(SkScalar radius, const SkMatrix& matrix)
41        : Sk2DPathEffect(matrix), fRadius(radius) {}
42
43    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(Dot2DPathEffect)
44
45protected:
46    void next(const SkPoint& loc, int u, int v, SkPath* dst) const override {
47        dst->addCircle(loc.fX, loc.fY, fRadius);
48    }
49
50    void flatten(SkWriteBuffer& buffer) const override {
51        this->INHERITED::flatten(buffer);
52        buffer.writeScalar(fRadius);
53    }
54
55private:
56    SkScalar fRadius;
57
58    typedef Sk2DPathEffect INHERITED;
59};
60
61class DemoView : public SampleView {
62public:
63    DemoView() {}
64
65protected:
66    // overrides from SkEventSink
67    virtual bool onQuery(SkEvent* evt) {
68        if (SampleCode::TitleQ(*evt)) {
69            SampleCode::TitleR(evt, "Demo");
70            return true;
71        }
72        return this->INHERITED::onQuery(evt);
73    }
74
75    virtual bool onClick(Click* click) {
76        return this->INHERITED::onClick(click);
77    }
78
79    void makePath(SkPath& path) {
80        path.addCircle(SkIntToScalar(20), SkIntToScalar(20), SkIntToScalar(20),
81            SkPath::kCCW_Direction);
82        for (int index = 0; index < 10; index++) {
83            SkScalar x = (float) cos(index / 10.0f * 2 * 3.1415925358f);
84            SkScalar y = (float) sin(index / 10.0f * 2 * 3.1415925358f);
85            x *= index & 1 ? 7 : 14;
86            y *= index & 1 ? 7 : 14;
87            x += SkIntToScalar(20);
88            y += SkIntToScalar(20);
89            if (index == 0)
90                path.moveTo(x, y);
91            else
92                path.lineTo(x, y);
93        }
94        path.close();
95    }
96
97    virtual void onDrawContent(SkCanvas* canvas) {
98        canvas->save();
99        this->drawPicture(canvas, 0);
100        canvas->restore();
101
102        {
103            SkPictureRecorder recorder;
104            {
105                SkCanvas* record = recorder.beginRecording(320, 480, nullptr, 0);
106                this->drawPicture(record, 120);
107            }
108            sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
109
110            canvas->translate(0, SkIntToScalar(120));
111
112            SkRect clip;
113            clip.set(0, 0, SkIntToScalar(160), SkIntToScalar(160));
114            do {
115                canvas->save();
116                canvas->clipRect(clip);
117                picture->playback(canvas);
118                canvas->restore();
119                if (clip.fRight < SkIntToScalar(320))
120                    clip.offset(SkIntToScalar(160), 0);
121                else if (clip.fBottom < SkIntToScalar(480))
122                    clip.offset(-SkIntToScalar(320), SkIntToScalar(160));
123                else
124                    break;
125            } while (true);
126        }
127    }
128
129    void drawPicture(SkCanvas* canvas, int spriteOffset) {
130        SkMatrix matrix; matrix.reset();
131        SkPaint paint;
132        SkPath path;
133        SkPoint start = {0, 0};
134        SkPoint stop = { SkIntToScalar(40), SkIntToScalar(40) };
135        SkRect rect = {0, 0, SkIntToScalar(40), SkIntToScalar(40) };
136        SkRect rect2 = {0, 0, SkIntToScalar(65), SkIntToScalar(20) };
137        SkScalar left = 0, top = 0, x = 0, y = 0;
138        int index;
139
140        char ascii[] = "ascii...";
141        int asciiLength = sizeof(ascii) - 1;
142        char utf8[] = "utf8" "\xe2\x80\xa6";
143        short utf16[] = {'u', 't', 'f', '1', '6', 0x2026 };
144        short utf16simple[] = {'u', 't', 'f', '1', '6', '!' };
145
146        makePath(path);
147        SkTDArray<SkPoint> pos;
148        pos.setCount(asciiLength);
149        for (index = 0;  index < asciiLength; index++)
150            pos[index].set(SkIntToScalar((unsigned int)index * 10),
151                                       SkIntToScalar((unsigned int)index * 2));
152        SkTDArray<SkPoint> pos2;
153        pos2.setCount(asciiLength);
154        for (index = 0;  index < asciiLength; index++)
155            pos2[index].set(SkIntToScalar((unsigned int)index * 10),
156                                        SkIntToScalar(20));
157
158        // shaders
159        SkPoint linearPoints[] = { { 0, 0, }, { SkIntToScalar(40), SkIntToScalar(40) } };
160        SkColor linearColors[] = { SK_ColorRED, SK_ColorBLUE };
161        SkScalar* linearPos = nullptr;
162        int linearCount = 2;
163        SkShader::TileMode linearMode = SkShader::kMirror_TileMode;
164        auto linear = SkGradientShader::MakeLinear(linearPoints,
165            linearColors, linearPos, linearCount, linearMode);
166
167        SkPoint radialCenter = { SkIntToScalar(25), SkIntToScalar(25) };
168        SkScalar radialRadius = SkIntToScalar(25);
169        SkColor radialColors[] = { SK_ColorGREEN, SK_ColorGRAY, SK_ColorRED };
170        SkScalar radialPos[] = { 0, SkIntToScalar(3) / 5, SkIntToScalar(1)};
171        int radialCount = 3;
172        SkShader::TileMode radialMode = SkShader::kRepeat_TileMode;
173        auto radial = SkGradientShader::MakeRadial(radialCenter,
174            radialRadius, radialColors, radialPos, radialCount,
175            radialMode);
176
177        SkEmbossMaskFilter::Light light;
178        light.fDirection[0] = SK_Scalar1/2;
179        light.fDirection[1] = SK_Scalar1/2;
180        light.fDirection[2] = SK_Scalar1/3;
181        light.fAmbient        = 0x48;
182        light.fSpecular        = 0x80;
183
184        auto lightingFilter = SkColorMatrixFilter::MakeLightingFilter(
185            0xff89bc45, 0xff112233);
186
187        canvas->save();
188        canvas->translate(SkIntToScalar(0), SkIntToScalar(5));
189        paint.setAntiAlias(true);
190        paint.setFilterQuality(kLow_SkFilterQuality);
191        // !!! draw through a clip
192        paint.setColor(SK_ColorLTGRAY);
193        paint.setStyle(SkPaint::kFill_Style);
194        SkRect clip = {0, 0, SkIntToScalar(320), SkIntToScalar(120)};
195        canvas->clipRect(clip);
196        paint.setShader(SkShader::MakeBitmapShader(fTx,
197            SkShader::kMirror_TileMode, SkShader::kRepeat_TileMode));
198        canvas->drawPaint(paint);
199        canvas->save();
200
201        // line (exercises xfermode, colorShader, colorFilter, filterShader)
202        paint.setColor(SK_ColorGREEN);
203        paint.setStrokeWidth(SkIntToScalar(10));
204        paint.setStyle(SkPaint::kStroke_Style);
205        paint.setBlendMode(SkBlendMode::kXor);
206        paint.setColorFilter(lightingFilter);
207        canvas->drawLine(start, stop, paint); // should not be green
208        paint.setBlendMode(SkBlendMode::kSrcOver);
209        paint.setColorFilter(nullptr);
210
211        // rectangle
212        paint.setStyle(SkPaint::kFill_Style);
213        canvas->translate(SkIntToScalar(50), 0);
214        paint.setColor(SK_ColorYELLOW);
215        paint.setShader(linear);
216        paint.setPathEffect(pathEffectTest());
217        canvas->drawRect(rect, paint);
218        paint.setPathEffect(nullptr);
219
220        // circle w/ emboss & transparent (exercises 3dshader)
221        canvas->translate(SkIntToScalar(50), 0);
222        paint.setMaskFilter(SkEmbossMaskFilter::Make(
223                                     SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(12)/5), light));
224        canvas->drawOval(rect, paint);
225        canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
226//        paint.setShader(transparentShader)->unref();
227        canvas->drawOval(rect, paint);
228        canvas->translate(0, SkIntToScalar(-10));
229
230        // path
231        canvas->translate(SkIntToScalar(50), 0);
232        paint.setColor(SK_ColorRED);
233        paint.setStyle(SkPaint::kStroke_Style);
234        paint.setStrokeWidth(SkIntToScalar(5));
235        paint.setShader(radial);
236        paint.setMaskFilter(nullptr);
237        canvas->drawPath(path, paint);
238
239        paint.setShader(nullptr);
240        // bitmap
241        canvas->translate(SkIntToScalar(50), 0);
242        paint.setStyle(SkPaint::kFill_Style);
243        canvas->drawBitmap(fBug, left, top, &paint);
244
245        canvas->translate(-SkIntToScalar(30), SkIntToScalar(30));
246        paint.setShader(shaderTest()); // test compose shader
247        canvas->drawRect(rect2, paint);
248        paint.setShader(nullptr);
249
250        canvas->restore();
251        // text
252        canvas->translate(0, SkIntToScalar(60));
253        canvas->save();
254        paint.setColor(SK_ColorGRAY);
255        canvas->drawPosText(ascii, asciiLength, pos.begin(), paint);
256        canvas->drawPosText(ascii, asciiLength, pos2.begin(), paint);
257
258        canvas->translate(SkIntToScalar(50), 0);
259        paint.setColor(SK_ColorCYAN);
260        canvas->drawText(utf8, sizeof(utf8) - 1, x, y, paint);
261
262        canvas->translate(SkIntToScalar(30), 0);
263        paint.setColor(SK_ColorMAGENTA);
264        paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
265        matrix.setTranslate(SkIntToScalar(10), SkIntToScalar(10));
266        canvas->drawTextOnPath((void*) utf16, sizeof(utf16), path, &matrix, paint);
267        canvas->translate(0, SkIntToScalar(20));
268        canvas->drawTextOnPath((void*) utf16simple, sizeof(utf16simple), path, &matrix, paint);
269        canvas->restore();
270
271        canvas->translate(0, SkIntToScalar(60));
272        paint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
273        canvas->restore();
274    }
275
276    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) {
277        fClickPt.set(x, y);
278        return this->INHERITED::onFindClickHandler(x, y, modi);
279    }
280
281    sk_sp<SkPathEffect> pathEffectTest() {
282        static const int gXY[] = { 1, 0, 0, -1, 2, -1, 3, 0, 2, 1, 0, 1 };
283        SkScalar gPhase = 0;
284        SkPath path;
285        path.moveTo(SkIntToScalar(gXY[0]), SkIntToScalar(gXY[1]));
286        for (unsigned i = 2; i < SK_ARRAY_COUNT(gXY); i += 2)
287            path.lineTo(SkIntToScalar(gXY[i]), SkIntToScalar(gXY[i+1]));
288        path.close();
289        path.offset(SkIntToScalar(-6), 0);
290        auto outer = SkPath1DPathEffect::Make(path, SkIntToScalar(12),
291            gPhase, SkPath1DPathEffect::kRotate_Style);
292        auto inner = SkDiscretePathEffect::Make(SkIntToScalar(2),
293            SkIntToScalar(1)/10); // SkCornerPathEffect(SkIntToScalar(2));
294        return SkPathEffect::MakeCompose(outer, inner);
295    }
296
297    sk_sp<SkShader> shaderTest() {
298        SkPoint pts[] = { { 0, 0, }, { SkIntToScalar(100), 0 } };
299        SkColor colors[] = { SK_ColorRED, SK_ColorBLUE };
300        auto shaderA = SkGradientShader::MakeLinear(pts, colors, nullptr,
301            2, SkShader::kClamp_TileMode);
302        pts[1].set(0, SkIntToScalar(100));
303        SkColor colors2[] = {SK_ColorBLACK,  SkColorSetARGB(0x80, 0, 0, 0)};
304        auto shaderB = SkGradientShader::MakeLinear(pts, colors2, nullptr,
305            2, SkShader::kClamp_TileMode);
306        return SkShader::MakeComposeShader(std::move(shaderA), std::move(shaderB),
307                                           SkBlendMode::kDstIn);
308    }
309
310    virtual void startTest() {
311        decode_file("/Users/caryclark/Desktop/bugcirc.gif", &fBug);
312        decode_file("/Users/caryclark/Desktop/tbcirc.gif", &fTb);
313        decode_file("/Users/caryclark/Desktop/05psp04.gif", &fTx);
314    }
315
316private:
317    SkPoint fClickPt;
318    SkBitmap fBug, fTb, fTx;
319    typedef SampleView INHERITED;
320};
321
322//////////////////////////////////////////////////////////////////////////////
323
324static SkView* MyFactory() { return new DemoView; }
325static SkViewRegister reg(MyFactory);
326