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 "SkLayerRasterizer.h"
24#include "SkMath.h"
25#include "SkPath.h"
26#include "SkPictureRecorder.h"
27#include "SkRegion.h"
28#include "SkShader.h"
29#include "SkCornerPathEffect.h"
30#include "SkPathMeasure.h"
31#include "SkPicture.h"
32#include "SkRandom.h"
33#include "SkTypeface.h"
34#include "SkUtils.h"
35
36#include <math.h>
37#include "DecodeFile.h"
38
39static void r0(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) {
40    p.setMaskFilter(SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
41                                           SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(3)),
42                                           SkBlurMaskFilter::kNone_BlurFlag));
43    rastBuilder->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
44
45    p.setMaskFilter(nullptr);
46    p.setStyle(SkPaint::kStroke_Style);
47    p.setStrokeWidth(SK_Scalar1);
48    rastBuilder->addLayer(p);
49
50    p.setAlpha(0x11);
51    p.setStyle(SkPaint::kFill_Style);
52    p.setBlendMode(SkBlendMode::kSrc);
53    rastBuilder->addLayer(p);
54}
55
56static void r1(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) {
57    rastBuilder->addLayer(p);
58
59    p.setAlpha(0x40);
60    p.setBlendMode(SkBlendMode::kSrc);
61    p.setStyle(SkPaint::kStroke_Style);
62    p.setStrokeWidth(SK_Scalar1*2);
63    rastBuilder->addLayer(p);
64}
65
66static void r2(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) {
67    p.setStyle(SkPaint::kStrokeAndFill_Style);
68    p.setStrokeWidth(SK_Scalar1*4);
69    rastBuilder->addLayer(p);
70
71    p.setStyle(SkPaint::kStroke_Style);
72    p.setStrokeWidth(SK_Scalar1*3/2);
73    p.setBlendMode(SkBlendMode::kClear);
74    rastBuilder->addLayer(p);
75}
76
77static void r3(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) {
78    p.setStyle(SkPaint::kStroke_Style);
79    p.setStrokeWidth(SK_Scalar1*3);
80    rastBuilder->addLayer(p);
81
82    p.setAlpha(0x20);
83    p.setStyle(SkPaint::kFill_Style);
84    p.setBlendMode(SkBlendMode::kSrc);
85    rastBuilder->addLayer(p);
86}
87
88static void r4(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) {
89    p.setAlpha(0x60);
90    rastBuilder->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
91
92    p.setAlpha(0xFF);
93    p.setBlendMode(SkBlendMode::kClear);
94    rastBuilder->addLayer(p, SK_Scalar1*3/2, SK_Scalar1*3/2);
95
96    p.setBlendMode(SkBlendMode::kSrcOver);
97    rastBuilder->addLayer(p);
98}
99
100static void r5(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) {
101    rastBuilder->addLayer(p);
102
103    p.setPathEffect(SkDiscretePathEffect::Make(SK_Scalar1*4, SK_Scalar1*3));
104    p.setBlendMode(SkBlendMode::kSrcOut);
105    rastBuilder->addLayer(p);
106}
107
108static void r6(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) {
109    rastBuilder->addLayer(p);
110
111    p.setAntiAlias(false);
112    SkLayerRasterizer::Builder rastBuilder2;
113    r5(&rastBuilder2, p);
114    p.setRasterizer(rastBuilder2.detach());
115    p.setBlendMode(SkBlendMode::kClear);
116    rastBuilder->addLayer(p);
117}
118
119class Dot2DPathEffect : public Sk2DPathEffect {
120public:
121    Dot2DPathEffect(SkScalar radius, const SkMatrix& matrix)
122        : Sk2DPathEffect(matrix), fRadius(radius) {}
123
124    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(Dot2DPathEffect)
125
126protected:
127    void next(const SkPoint& loc, int u, int v, SkPath* dst) const override {
128        dst->addCircle(loc.fX, loc.fY, fRadius);
129    }
130
131    void flatten(SkWriteBuffer& buffer) const override {
132        this->INHERITED::flatten(buffer);
133        buffer.writeScalar(fRadius);
134    }
135
136private:
137    SkScalar fRadius;
138
139    typedef Sk2DPathEffect INHERITED;
140};
141
142static void r7(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) {
143    SkMatrix    lattice;
144    lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
145    lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
146    p.setPathEffect(sk_make_sp<Dot2DPathEffect>(SK_Scalar1*4, lattice));
147    rastBuilder->addLayer(p);
148}
149
150static void r8(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) {
151    rastBuilder->addLayer(p);
152
153    SkMatrix    lattice;
154    lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
155    lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
156    p.setPathEffect(sk_make_sp<Dot2DPathEffect>(SK_Scalar1*2, lattice));
157    p.setBlendMode(SkBlendMode::kClear);
158    rastBuilder->addLayer(p);
159
160    p.setPathEffect(nullptr);
161    p.setBlendMode(SkBlendMode::kSrcOver);
162    p.setStyle(SkPaint::kStroke_Style);
163    p.setStrokeWidth(SK_Scalar1);
164    rastBuilder->addLayer(p);
165}
166
167static void r9(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) {
168    rastBuilder->addLayer(p);
169
170    SkMatrix    lattice;
171    lattice.setScale(SK_Scalar1, SK_Scalar1*6, 0, 0);
172    lattice.postRotate(SkIntToScalar(30), 0, 0);
173    p.setPathEffect(SkLine2DPathEffect::Make(SK_Scalar1*2, lattice));
174    p.setBlendMode(SkBlendMode::kClear);
175    rastBuilder->addLayer(p);
176
177    p.setPathEffect(nullptr);
178    p.setBlendMode(SkBlendMode::kSrcOver);
179    p.setStyle(SkPaint::kStroke_Style);
180    p.setStrokeWidth(SK_Scalar1);
181    rastBuilder->addLayer(p);
182}
183
184typedef void (*raster_proc)(SkLayerRasterizer::Builder*, SkPaint&);
185
186static const raster_proc gRastProcs[] = {
187    r0, r1, r2, r3, r4, r5, r6, r7, r8, r9
188};
189
190static const struct {
191    SkColor fMul, fAdd;
192} gLightingColors[] = {
193    { 0x808080, 0x800000 }, // general case
194    { 0x707070, 0x707070 }, // no-pin case
195    { 0xFFFFFF, 0x800000 }, // just-add case
196    { 0x808080, 0x000000 }, // just-mul case
197    { 0xFFFFFF, 0x000000 }  // identity case
198};
199
200static void apply_shader(SkPaint* paint, int index) {
201    raster_proc proc = gRastProcs[index];
202    if (proc) {
203        SkPaint p;
204        SkLayerRasterizer::Builder rastBuilder;
205
206        p.setAntiAlias(true);
207        proc(&rastBuilder, p);
208        paint->setRasterizer(rastBuilder.detach());
209    }
210
211#ifdef SK_SUPPORT_LEGACY_EMBOSSMASKFILTER
212    SkScalar dir[] = { SK_Scalar1, SK_Scalar1, SK_Scalar1 };
213    paint->setMaskFilter(SkBlurMaskFilter::MakeEmboss(
214                SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(3)), dir,
215                SK_Scalar1/4, SkIntToScalar(4)));
216    paint->setColor(SK_ColorBLUE);
217#endif
218}
219
220class DemoView : public SampleView {
221public:
222    DemoView() {}
223
224protected:
225    // overrides from SkEventSink
226    virtual bool onQuery(SkEvent* evt) {
227        if (SampleCode::TitleQ(*evt)) {
228            SampleCode::TitleR(evt, "Demo");
229            return true;
230        }
231        return this->INHERITED::onQuery(evt);
232    }
233
234    virtual bool onClick(Click* click) {
235        return this->INHERITED::onClick(click);
236    }
237
238    void makePath(SkPath& path) {
239        path.addCircle(SkIntToScalar(20), SkIntToScalar(20), SkIntToScalar(20),
240            SkPath::kCCW_Direction);
241        for (int index = 0; index < 10; index++) {
242            SkScalar x = (float) cos(index / 10.0f * 2 * 3.1415925358f);
243            SkScalar y = (float) sin(index / 10.0f * 2 * 3.1415925358f);
244            x *= index & 1 ? 7 : 14;
245            y *= index & 1 ? 7 : 14;
246            x += SkIntToScalar(20);
247            y += SkIntToScalar(20);
248            if (index == 0)
249                path.moveTo(x, y);
250            else
251                path.lineTo(x, y);
252        }
253        path.close();
254    }
255
256    virtual void onDrawContent(SkCanvas* canvas) {
257        canvas->save();
258        this->drawPicture(canvas, 0);
259        canvas->restore();
260
261        {
262            SkPictureRecorder recorder;
263            {
264                SkCanvas* record = recorder.beginRecording(320, 480, nullptr, 0);
265                this->drawPicture(record, 120);
266            }
267            sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
268
269            canvas->translate(0, SkIntToScalar(120));
270
271            SkRect clip;
272            clip.set(0, 0, SkIntToScalar(160), SkIntToScalar(160));
273            do {
274                canvas->save();
275                canvas->clipRect(clip);
276                picture->playback(canvas);
277                canvas->restore();
278                if (clip.fRight < SkIntToScalar(320))
279                    clip.offset(SkIntToScalar(160), 0);
280                else if (clip.fBottom < SkIntToScalar(480))
281                    clip.offset(-SkIntToScalar(320), SkIntToScalar(160));
282                else
283                    break;
284            } while (true);
285        }
286    }
287
288    void drawPicture(SkCanvas* canvas, int spriteOffset) {
289        SkMatrix matrix; matrix.reset();
290        SkPaint paint;
291        SkPath path;
292        SkPoint start = {0, 0};
293        SkPoint stop = { SkIntToScalar(40), SkIntToScalar(40) };
294        SkRect rect = {0, 0, SkIntToScalar(40), SkIntToScalar(40) };
295        SkRect rect2 = {0, 0, SkIntToScalar(65), SkIntToScalar(20) };
296        SkScalar left = 0, top = 0, x = 0, y = 0;
297        int index;
298
299        char ascii[] = "ascii...";
300        int asciiLength = sizeof(ascii) - 1;
301        char utf8[] = "utf8" "\xe2\x80\xa6";
302        short utf16[] = {'u', 't', 'f', '1', '6', 0x2026 };
303        short utf16simple[] = {'u', 't', 'f', '1', '6', '!' };
304
305        makePath(path);
306        SkTDArray<SkPoint>(pos);
307        pos.setCount(asciiLength);
308        for (index = 0;  index < asciiLength; index++)
309            pos[index].set(SkIntToScalar((unsigned int)index * 10),
310                                       SkIntToScalar((unsigned int)index * 2));
311        SkTDArray<SkPoint>(pos2);
312        pos2.setCount(asciiLength);
313        for (index = 0;  index < asciiLength; index++)
314            pos2[index].set(SkIntToScalar((unsigned int)index * 10),
315                                        SkIntToScalar(20));
316
317        // shaders
318        SkPoint linearPoints[] = { { 0, 0, }, { SkIntToScalar(40), SkIntToScalar(40) } };
319        SkColor linearColors[] = { SK_ColorRED, SK_ColorBLUE };
320        SkScalar* linearPos = nullptr;
321        int linearCount = 2;
322        SkShader::TileMode linearMode = SkShader::kMirror_TileMode;
323        auto linear = SkGradientShader::MakeLinear(linearPoints,
324            linearColors, linearPos, linearCount, linearMode);
325
326        SkPoint radialCenter = { SkIntToScalar(25), SkIntToScalar(25) };
327        SkScalar radialRadius = SkIntToScalar(25);
328        SkColor radialColors[] = { SK_ColorGREEN, SK_ColorGRAY, SK_ColorRED };
329        SkScalar radialPos[] = { 0, SkIntToScalar(3) / 5, SkIntToScalar(1)};
330        int radialCount = 3;
331        SkShader::TileMode radialMode = SkShader::kRepeat_TileMode;
332        auto radial = SkGradientShader::MakeRadial(radialCenter,
333            radialRadius, radialColors, radialPos, radialCount,
334            radialMode);
335
336        SkEmbossMaskFilter::Light light;
337        light.fDirection[0] = SK_Scalar1/2;
338        light.fDirection[1] = SK_Scalar1/2;
339        light.fDirection[2] = SK_Scalar1/3;
340        light.fAmbient        = 0x48;
341        light.fSpecular        = 0x80;
342
343        auto lightingFilter = SkColorMatrixFilter::MakeLightingFilter(
344            0xff89bc45, 0xff112233);
345
346        canvas->save();
347        canvas->translate(SkIntToScalar(0), SkIntToScalar(5));
348        paint.setAntiAlias(true);
349        paint.setFilterQuality(kLow_SkFilterQuality);
350        // !!! draw through a clip
351        paint.setColor(SK_ColorLTGRAY);
352        paint.setStyle(SkPaint::kFill_Style);
353        SkRect clip = {0, 0, SkIntToScalar(320), SkIntToScalar(120)};
354        canvas->clipRect(clip);
355        paint.setShader(SkShader::MakeBitmapShader(fTx,
356            SkShader::kMirror_TileMode, SkShader::kRepeat_TileMode));
357        canvas->drawPaint(paint);
358        canvas->save();
359
360        // line (exercises xfermode, colorShader, colorFilter, filterShader)
361        paint.setColor(SK_ColorGREEN);
362        paint.setStrokeWidth(SkIntToScalar(10));
363        paint.setStyle(SkPaint::kStroke_Style);
364        paint.setBlendMode(SkBlendMode::kXor);
365        paint.setColorFilter(lightingFilter);
366        canvas->drawLine(start, stop, paint); // should not be green
367        paint.setBlendMode(SkBlendMode::kSrcOver);
368        paint.setColorFilter(nullptr);
369
370        // rectangle
371        paint.setStyle(SkPaint::kFill_Style);
372        canvas->translate(SkIntToScalar(50), 0);
373        paint.setColor(SK_ColorYELLOW);
374        paint.setShader(linear);
375        paint.setPathEffect(pathEffectTest());
376        canvas->drawRect(rect, paint);
377        paint.setPathEffect(nullptr);
378
379        // circle w/ emboss & transparent (exercises 3dshader)
380        canvas->translate(SkIntToScalar(50), 0);
381        paint.setMaskFilter(SkEmbossMaskFilter::Make(
382                                     SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(12)/5), light));
383        canvas->drawOval(rect, paint);
384        canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
385//        paint.setShader(transparentShader)->unref();
386        canvas->drawOval(rect, paint);
387        canvas->translate(0, SkIntToScalar(-10));
388
389        // path
390        canvas->translate(SkIntToScalar(50), 0);
391        paint.setColor(SK_ColorRED);
392        paint.setStyle(SkPaint::kStroke_Style);
393        paint.setStrokeWidth(SkIntToScalar(5));
394        paint.setShader(radial);
395        paint.setMaskFilter(nullptr);
396        canvas->drawPath(path, paint);
397
398        paint.setShader(nullptr);
399        // bitmap
400        canvas->translate(SkIntToScalar(50), 0);
401        paint.setStyle(SkPaint::kFill_Style);
402        canvas->drawBitmap(fBug, left, top, &paint);
403
404        canvas->translate(-SkIntToScalar(30), SkIntToScalar(30));
405        paint.setShader(shaderTest()); // test compose shader
406        canvas->drawRect(rect2, paint);
407        paint.setShader(nullptr);
408
409        canvas->restore();
410        // text
411        canvas->translate(0, SkIntToScalar(60));
412        canvas->save();
413        paint.setColor(SK_ColorGRAY);
414        canvas->drawPosText(ascii, asciiLength, pos.begin(), paint);
415        canvas->drawPosText(ascii, asciiLength, pos2.begin(), paint);
416
417        canvas->translate(SkIntToScalar(50), 0);
418        paint.setColor(SK_ColorCYAN);
419        canvas->drawText(utf8, sizeof(utf8) - 1, x, y, paint);
420
421        canvas->translate(SkIntToScalar(30), 0);
422        paint.setColor(SK_ColorMAGENTA);
423        paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
424        matrix.setTranslate(SkIntToScalar(10), SkIntToScalar(10));
425        canvas->drawTextOnPath((void*) utf16, sizeof(utf16), path, &matrix, paint);
426        canvas->translate(0, SkIntToScalar(20));
427        canvas->drawTextOnPath((void*) utf16simple, sizeof(utf16simple), path, &matrix, paint);
428        canvas->restore();
429
430        canvas->translate(0, SkIntToScalar(60));
431        paint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
432        canvas->restore();
433    }
434
435    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) {
436        fClickPt.set(x, y);
437        this->inval(nullptr);
438        return this->INHERITED::onFindClickHandler(x, y, modi);
439    }
440
441    sk_sp<SkPathEffect> pathEffectTest() {
442        static const int gXY[] = { 1, 0, 0, -1, 2, -1, 3, 0, 2, 1, 0, 1 };
443        SkScalar gPhase = 0;
444        SkPath path;
445        path.moveTo(SkIntToScalar(gXY[0]), SkIntToScalar(gXY[1]));
446        for (unsigned i = 2; i < SK_ARRAY_COUNT(gXY); i += 2)
447            path.lineTo(SkIntToScalar(gXY[i]), SkIntToScalar(gXY[i+1]));
448        path.close();
449        path.offset(SkIntToScalar(-6), 0);
450        auto outer = SkPath1DPathEffect::Make(path, SkIntToScalar(12),
451            gPhase, SkPath1DPathEffect::kRotate_Style);
452        auto inner = SkDiscretePathEffect::Make(SkIntToScalar(2),
453            SkIntToScalar(1)/10); // SkCornerPathEffect(SkIntToScalar(2));
454        return SkPathEffect::MakeCompose(outer, inner);
455    }
456
457    sk_sp<SkShader> shaderTest() {
458        SkPoint pts[] = { { 0, 0, }, { SkIntToScalar(100), 0 } };
459        SkColor colors[] = { SK_ColorRED, SK_ColorBLUE };
460        auto shaderA = SkGradientShader::MakeLinear(pts, colors, nullptr,
461            2, SkShader::kClamp_TileMode);
462        pts[1].set(0, SkIntToScalar(100));
463        SkColor colors2[] = {SK_ColorBLACK,  SkColorSetARGB(0x80, 0, 0, 0)};
464        auto shaderB = SkGradientShader::MakeLinear(pts, colors2, nullptr,
465            2, SkShader::kClamp_TileMode);
466        return SkShader::MakeComposeShader(std::move(shaderA), std::move(shaderB),
467                                           SkBlendMode::kDstIn);
468    }
469
470    virtual void startTest() {
471        decode_file("/Users/caryclark/Desktop/bugcirc.gif", &fBug);
472        decode_file("/Users/caryclark/Desktop/tbcirc.gif", &fTb);
473        decode_file("/Users/caryclark/Desktop/05psp04.gif", &fTx);
474    }
475
476    void drawRaster(SkCanvas* canvas)  {
477        for (size_t index = 0; index < SK_ARRAY_COUNT(gRastProcs); index++)
478            drawOneRaster(canvas);
479    }
480
481    void drawOneRaster(SkCanvas* canvas) {
482        canvas->save();
483
484        SkScalar    x = SkIntToScalar(20);
485        SkScalar    y = SkIntToScalar(40);
486        SkPaint     paint;
487
488        paint.setAntiAlias(true);
489        paint.setTextSize(SkIntToScalar(48));
490        paint.setTypeface(SkTypeface::MakeFromName("sans-serif",
491                                                   SkFontStyle::FromOldStyle(SkTypeface::kBold)));
492
493        SkString str("GOOGLE");
494
495        for (size_t i = 0; i < SK_ARRAY_COUNT(gRastProcs); i++) {
496            apply_shader(&paint, (int)i);
497
498          //  paint.setMaskFilter(nullptr);
499          //  paint.setColor(SK_ColorBLACK);
500
501#if 01
502            int index = i % SK_ARRAY_COUNT(gLightingColors);
503            paint.setColorFilter(SkColorMatrixFilter::MakeLightingFilter(
504                                    gLightingColors[index].fMul,
505                                    gLightingColors[index].fAdd));
506#endif
507
508            canvas->drawString(str, x, y, paint);
509            SkRect  oval = { x, y - SkIntToScalar(40), x + SkIntToScalar(40), y };
510            paint.setStyle(SkPaint::kStroke_Style);
511            canvas->drawOval(oval, paint);
512            paint.setStyle(SkPaint::kFill_Style);
513
514            y += paint.getFontSpacing();
515        }
516
517        canvas->restore();
518    }
519
520private:
521    SkPoint fClickPt;
522    SkBitmap fBug, fTb, fTx;
523    typedef SampleView INHERITED;
524};
525
526//////////////////////////////////////////////////////////////////////////////
527
528static SkView* MyFactory() { return new DemoView; }
529static SkViewRegister reg(MyFactory);
530