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