Home | History | Annotate | Download | only in samplecode
      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 "SkBlurMaskFilter.h"
     11 #include "SkCanvas.h"
     12 #include "SkDevice.h"
     13 #include "SkReadBuffer.h"
     14 #include "SkWriteBuffer.h"
     15 #include "SkGradientShader.h"
     16 #include "SkLayerRasterizer.h"
     17 #include "SkPaint.h"
     18 #include "SkView.h"
     19 
     20 #define BG_COLOR    0xFFDDDDDD
     21 
     22 typedef void (*SlideProc)(SkCanvas*);
     23 
     24 ///////////////////////////////////////////////////////////////////////////////
     25 
     26 #include "Sk1DPathEffect.h"
     27 #include "Sk2DPathEffect.h"
     28 #include "SkCornerPathEffect.h"
     29 #include "SkDashPathEffect.h"
     30 #include "SkDiscretePathEffect.h"
     31 
     32 static void compose_pe(SkPaint* paint) {
     33     SkPathEffect* pe = paint->getPathEffect();
     34     SkPathEffect* corner = SkCornerPathEffect::Create(25);
     35     SkPathEffect* compose;
     36     if (pe) {
     37         compose = SkComposePathEffect::Create(pe, corner);
     38         corner->unref();
     39     } else {
     40         compose = corner;
     41     }
     42     paint->setPathEffect(compose)->unref();
     43 }
     44 
     45 static void hair_pe(SkPaint* paint) {
     46     paint->setStrokeWidth(0);
     47 }
     48 
     49 static void hair2_pe(SkPaint* paint) {
     50     paint->setStrokeWidth(0);
     51     compose_pe(paint);
     52 }
     53 
     54 static void stroke_pe(SkPaint* paint) {
     55     paint->setStrokeWidth(12);
     56     compose_pe(paint);
     57 }
     58 
     59 static void dash_pe(SkPaint* paint) {
     60     SkScalar inter[] = { 20, 10, 10, 10 };
     61     paint->setStrokeWidth(12);
     62     paint->setPathEffect(SkDashPathEffect::Create(inter, SK_ARRAY_COUNT(inter),
     63                                                   0))->unref();
     64     compose_pe(paint);
     65 }
     66 
     67 static const int gXY[] = {
     68 4, 0, 0, -4, 8, -4, 12, 0, 8, 4, 0, 4
     69 };
     70 
     71 static void scale(SkPath* path, SkScalar scale) {
     72     SkMatrix m;
     73     m.setScale(scale, scale);
     74     path->transform(m);
     75 }
     76 
     77 static void one_d_pe(SkPaint* paint) {
     78     SkPath  path;
     79     path.moveTo(SkIntToScalar(gXY[0]), SkIntToScalar(gXY[1]));
     80     for (unsigned i = 2; i < SK_ARRAY_COUNT(gXY); i += 2)
     81         path.lineTo(SkIntToScalar(gXY[i]), SkIntToScalar(gXY[i+1]));
     82     path.close();
     83     path.offset(SkIntToScalar(-6), 0);
     84     scale(&path, 1.5f);
     85 
     86     paint->setPathEffect(SkPath1DPathEffect::Create(path, SkIntToScalar(21), 0,
     87                                                     SkPath1DPathEffect::kRotate_Style))->unref();
     88     compose_pe(paint);
     89 }
     90 
     91 typedef void (*PE_Proc)(SkPaint*);
     92 static const PE_Proc gPE[] = { hair_pe, hair2_pe, stroke_pe, dash_pe, one_d_pe };
     93 
     94 static void fill_pe(SkPaint* paint) {
     95     paint->setStyle(SkPaint::kFill_Style);
     96     paint->setPathEffect(nullptr);
     97 }
     98 
     99 static void discrete_pe(SkPaint* paint) {
    100     paint->setPathEffect(SkDiscretePathEffect::Create(10, 4))->unref();
    101 }
    102 
    103 static SkPathEffect* MakeTileEffect() {
    104     SkMatrix m;
    105     m.setScale(SkIntToScalar(12), SkIntToScalar(12));
    106 
    107     SkPath path;
    108     path.addCircle(0, 0, SkIntToScalar(5));
    109 
    110     return SkPath2DPathEffect::Create(m, path);
    111 }
    112 
    113 static void tile_pe(SkPaint* paint) {
    114     paint->setPathEffect(MakeTileEffect())->unref();
    115 }
    116 
    117 static const PE_Proc gPE2[] = { fill_pe, discrete_pe, tile_pe };
    118 
    119 static void patheffect_slide(SkCanvas* canvas) {
    120     SkPaint paint;
    121     paint.setAntiAlias(true);
    122     paint.setStyle(SkPaint::kStroke_Style);
    123 
    124     SkPath path;
    125     path.moveTo(20, 20);
    126     path.lineTo(70, 120);
    127     path.lineTo(120, 30);
    128     path.lineTo(170, 80);
    129     path.lineTo(240, 50);
    130 
    131     size_t i;
    132     canvas->save();
    133     for (i = 0; i < SK_ARRAY_COUNT(gPE); i++) {
    134         gPE[i](&paint);
    135         canvas->drawPath(path, paint);
    136         canvas->translate(0, 75);
    137     }
    138     canvas->restore();
    139 
    140     path.reset();
    141     SkRect r = { 0, 0, 250, 120 };
    142     path.addOval(r, SkPath::kCW_Direction);
    143     r.inset(50, 50);
    144     path.addRect(r, SkPath::kCCW_Direction);
    145 
    146     canvas->translate(320, 20);
    147     for (i = 0; i < SK_ARRAY_COUNT(gPE2); i++) {
    148         gPE2[i](&paint);
    149         canvas->drawPath(path, paint);
    150         canvas->translate(0, 160);
    151     }
    152 }
    153 
    154 ///////////////////////////////////////////////////////////////////////////////
    155 
    156 #include "SkGradientShader.h"
    157 
    158 struct GradData {
    159     int             fCount;
    160     const SkColor*  fColors;
    161     const SkScalar* fPos;
    162 };
    163 
    164 static const SkColor gColors[] = {
    165 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
    166 };
    167 static const SkScalar gPos0[] = { 0, SK_Scalar1 };
    168 static const SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
    169 static const SkScalar gPos2[] = {
    170 0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1
    171 };
    172 
    173 static const GradData gGradData[] = {
    174 { 2, gColors, nullptr },
    175 { 2, gColors, gPos0 },
    176 { 2, gColors, gPos1 },
    177 { 5, gColors, nullptr },
    178 { 5, gColors, gPos2 }
    179 };
    180 
    181 static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
    182     return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos, data.fCount, tm);
    183 }
    184 
    185 static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
    186     SkPoint center;
    187     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
    188                SkScalarAve(pts[0].fY, pts[1].fY));
    189     return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
    190                                           data.fPos, data.fCount, tm);
    191 }
    192 
    193 static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
    194     SkPoint center;
    195     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
    196                SkScalarAve(pts[0].fY, pts[1].fY));
    197     return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors, data.fPos, data.fCount);
    198 }
    199 
    200 static SkShader* Make2Conical(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
    201     SkPoint center0, center1;
    202     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
    203                 SkScalarAve(pts[0].fY, pts[1].fY));
    204     center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
    205                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
    206     return SkGradientShader::CreateTwoPointConical(
    207                                                   center1, (pts[1].fX - pts[0].fX) / 7,
    208                                                   center0, (pts[1].fX - pts[0].fX) / 2,
    209                                                   data.fColors, data.fPos, data.fCount, tm);
    210 }
    211 
    212 typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm);
    213 static const GradMaker gGradMakers[] = {
    214     MakeLinear, MakeRadial, MakeSweep, Make2Conical
    215 };
    216 
    217 static void gradient_slide(SkCanvas* canvas) {
    218     SkPoint pts[2] = {
    219         { 0, 0 },
    220         { SkIntToScalar(100), SkIntToScalar(100) }
    221     };
    222     SkShader::TileMode tm = SkShader::kClamp_TileMode;
    223     SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
    224     SkPaint paint;
    225     paint.setAntiAlias(true);
    226     paint.setDither(true);
    227 
    228     canvas->translate(SkIntToScalar(20), SkIntToScalar(10));
    229     for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
    230         canvas->save();
    231         for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); j++) {
    232             SkShader* shader = gGradMakers[j](pts, gGradData[i], tm);
    233             paint.setShader(shader);
    234             canvas->drawRect(r, paint);
    235             shader->unref();
    236             canvas->translate(0, SkIntToScalar(120));
    237         }
    238         canvas->restore();
    239         canvas->translate(SkIntToScalar(120), 0);
    240     }
    241 }
    242 
    243 ///////////////////////////////////////////////////////////////////////////////
    244 
    245 #include "SkPathMeasure.h"
    246 
    247 static SkScalar getpathlen(const SkPath& path) {
    248     SkPathMeasure   meas(path, false);
    249     return meas.getLength();
    250 }
    251 
    252 static void textonpath_slide(SkCanvas* canvas) {
    253     const char* text = "Displacement";
    254     size_t len =strlen(text);
    255     SkPath path;
    256     path.moveTo(100, 300);
    257     path.quadTo(300, 100, 500, 300);
    258     path.offset(0, -100);
    259 
    260     SkPaint paint;
    261     paint.setAntiAlias(true);
    262     paint.setTextSize(40);
    263 
    264     paint.setStyle(SkPaint::kStroke_Style);
    265     canvas->drawPath(path, paint);
    266     paint.setStyle(SkPaint::kFill_Style);
    267 
    268     SkScalar x = 50;
    269     paint.setColor(0xFF008800);
    270     canvas->drawTextOnPathHV(text, len, path,
    271                              x, paint.getTextSize()*2/3, paint);
    272     paint.setColor(SK_ColorRED);
    273     canvas->drawTextOnPathHV(text, len, path,
    274                              x + 60, 0, paint);
    275     paint.setColor(SK_ColorBLUE);
    276     canvas->drawTextOnPathHV(text, len, path,
    277                              x + 120, -paint.getTextSize()*2/3, paint);
    278 
    279     path.offset(0, 200);
    280     paint.setTextAlign(SkPaint::kRight_Align);
    281 
    282     text = "Matrices";
    283     len = strlen(text);
    284     SkScalar pathLen = getpathlen(path);
    285     SkMatrix matrix;
    286 
    287     paint.setColor(SK_ColorBLACK);
    288     paint.setStyle(SkPaint::kStroke_Style);
    289     canvas->drawPath(path, paint);
    290     paint.setStyle(SkPaint::kFill_Style);
    291 
    292     paint.setTextSize(50);
    293     canvas->drawTextOnPath(text, len, path, nullptr, paint);
    294 
    295     paint.setColor(SK_ColorRED);
    296     matrix.setScale(-SK_Scalar1, SK_Scalar1);
    297     matrix.postTranslate(pathLen, 0);
    298     canvas->drawTextOnPath(text, len, path, &matrix, paint);
    299 
    300     paint.setColor(SK_ColorBLUE);
    301     matrix.setScale(SK_Scalar1, -SK_Scalar1);
    302     canvas->drawTextOnPath(text, len, path, &matrix, paint);
    303 
    304     paint.setColor(0xFF008800);
    305     matrix.setScale(-SK_Scalar1, -SK_Scalar1);
    306     matrix.postTranslate(pathLen, 0);
    307     canvas->drawTextOnPath(text, len, path, &matrix, paint);
    308 }
    309 
    310 ///////////////////////////////////////////////////////////////////////////////
    311 
    312 #include "SkImageDecoder.h"
    313 #include "SkOSFile.h"
    314 #include "SkRandom.h"
    315 #include "SkStream.h"
    316 
    317 static SkShader* make_shader0(SkIPoint* size) {
    318     SkBitmap    bm;
    319 
    320     SkImageDecoder::DecodeFile("/skimages/logo.gif", &bm);
    321     size->set(bm.width(), bm.height());
    322     return SkShader::CreateBitmapShader(bm, SkShader::kClamp_TileMode,
    323                                         SkShader::kClamp_TileMode);
    324 }
    325 
    326 static SkShader* make_shader1(const SkIPoint& size) {
    327     SkPoint pts[] = { { 0, 0 },
    328                       { SkIntToScalar(size.fX), SkIntToScalar(size.fY) } };
    329     SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorRED };
    330     return SkGradientShader::CreateLinear(pts, colors, nullptr,
    331                                           SK_ARRAY_COUNT(colors), SkShader::kMirror_TileMode);
    332 }
    333 
    334 class Rec {
    335 public:
    336     SkCanvas::VertexMode    fMode;
    337     int                     fCount;
    338     SkPoint*                fVerts;
    339     SkPoint*                fTexs;
    340 
    341     Rec() : fCount(0), fVerts(nullptr), fTexs(nullptr) {}
    342     ~Rec() { delete[] fVerts; delete[] fTexs; }
    343 };
    344 
    345 static void make_tris(Rec* rec) {
    346     int n = 10;
    347     SkRandom    rand;
    348 
    349     rec->fMode = SkCanvas::kTriangles_VertexMode;
    350     rec->fCount = n * 3;
    351     rec->fVerts = new SkPoint[rec->fCount];
    352 
    353     for (int i = 0; i < n; i++) {
    354         SkPoint* v = &rec->fVerts[i*3];
    355         for (int j = 0; j < 3; j++) {
    356             v[j].set(rand.nextUScalar1() * 250, rand.nextUScalar1() * 250);
    357         }
    358     }
    359 }
    360 
    361 static void make_fan(Rec* rec, int texWidth, int texHeight) {
    362     const SkScalar tx = SkIntToScalar(texWidth);
    363     const SkScalar ty = SkIntToScalar(texHeight);
    364     const int n = 24;
    365 
    366     rec->fMode = SkCanvas::kTriangleFan_VertexMode;
    367     rec->fCount = n + 2;
    368     rec->fVerts = new SkPoint[rec->fCount];
    369     rec->fTexs  = new SkPoint[rec->fCount];
    370 
    371     SkPoint* v = rec->fVerts;
    372     SkPoint* t = rec->fTexs;
    373 
    374     v[0].set(0, 0);
    375     t[0].set(0, 0);
    376     for (int i = 0; i < n; i++) {
    377         SkScalar cos;
    378         SkScalar sin = SkScalarSinCos(SK_ScalarPI * 2 * i / n, &cos);
    379         v[i+1].set(cos, sin);
    380         t[i+1].set(i*tx/n, ty);
    381     }
    382     v[n+1] = v[1];
    383     t[n+1].set(tx, ty);
    384 
    385     SkMatrix m;
    386     m.setScale(SkIntToScalar(100), SkIntToScalar(100));
    387     m.postTranslate(SkIntToScalar(110), SkIntToScalar(110));
    388     m.mapPoints(v, rec->fCount);
    389 }
    390 
    391 static void make_strip(Rec* rec, int texWidth, int texHeight) {
    392     const SkScalar tx = SkIntToScalar(texWidth);
    393     const SkScalar ty = SkIntToScalar(texHeight);
    394     const int n = 24;
    395 
    396     rec->fMode = SkCanvas::kTriangleStrip_VertexMode;
    397     rec->fCount = 2 * (n + 1);
    398     rec->fVerts = new SkPoint[rec->fCount];
    399     rec->fTexs  = new SkPoint[rec->fCount];
    400 
    401     SkPoint* v = rec->fVerts;
    402     SkPoint* t = rec->fTexs;
    403 
    404     for (int i = 0; i < n; i++) {
    405         SkScalar cos;
    406         SkScalar sin = SkScalarSinCos(SK_ScalarPI * 2 * i / n, &cos);
    407         v[i*2 + 0].set(cos/2, sin/2);
    408         v[i*2 + 1].set(cos, sin);
    409 
    410         t[i*2 + 0].set(tx * i / n, ty);
    411         t[i*2 + 1].set(tx * i / n, 0);
    412     }
    413     v[2*n + 0] = v[0];
    414     v[2*n + 1] = v[1];
    415 
    416     t[2*n + 0].set(tx, ty);
    417     t[2*n + 1].set(tx, 0);
    418 
    419     SkMatrix m;
    420     m.setScale(SkIntToScalar(100), SkIntToScalar(100));
    421     m.postTranslate(SkIntToScalar(110), SkIntToScalar(110));
    422     m.mapPoints(v, rec->fCount);
    423 }
    424 
    425 static void mesh_slide(SkCanvas* canvas) {
    426     Rec fRecs[3];
    427     SkIPoint    size;
    428 
    429     SkShader* fShader0 = make_shader0(&size);
    430     SkShader* fShader1 = make_shader1(size);
    431 
    432     SkAutoUnref aur0(fShader0);
    433     SkAutoUnref aur1(fShader1);
    434 
    435     make_strip(&fRecs[0], size.fX, size.fY);
    436     make_fan(&fRecs[1], size.fX, size.fY);
    437     make_tris(&fRecs[2]);
    438 
    439     SkPaint paint;
    440     paint.setDither(true);
    441     paint.setFilterQuality(kLow_SkFilterQuality);
    442 
    443     for (size_t i = 0; i < SK_ARRAY_COUNT(fRecs); i++) {
    444         canvas->save();
    445 
    446         paint.setShader(nullptr);
    447         canvas->drawVertices(fRecs[i].fMode, fRecs[i].fCount,
    448                              fRecs[i].fVerts, fRecs[i].fTexs,
    449                              nullptr, nullptr, nullptr, 0, paint);
    450 
    451         canvas->translate(SkIntToScalar(210), 0);
    452 
    453         paint.setShader(fShader0);
    454         canvas->drawVertices(fRecs[i].fMode, fRecs[i].fCount,
    455                              fRecs[i].fVerts, fRecs[i].fTexs,
    456                              nullptr, nullptr, nullptr, 0, paint);
    457 
    458         canvas->translate(SkIntToScalar(210), 0);
    459 
    460         paint.setShader(fShader1);
    461         canvas->drawVertices(fRecs[i].fMode, fRecs[i].fCount,
    462                              fRecs[i].fVerts, fRecs[i].fTexs,
    463                              nullptr, nullptr, nullptr, 0, paint);
    464         canvas->restore();
    465 
    466         canvas->translate(0, SkIntToScalar(250));
    467     }
    468 }
    469 
    470 ///////////////////////////////////////////////////////////////////////////////
    471 
    472 static void r0(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p)
    473 {
    474     p.setMaskFilter(SkBlurMaskFilter::Create(kNormal_SkBlurStyle,
    475                                              SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(3))))->unref();
    476     rastBuilder->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
    477 
    478     p.setMaskFilter(nullptr);
    479     p.setStyle(SkPaint::kStroke_Style);
    480     p.setStrokeWidth(SK_Scalar1);
    481     rastBuilder->addLayer(p);
    482 
    483     p.setAlpha(0x11);
    484     p.setStyle(SkPaint::kFill_Style);
    485     p.setXfermodeMode(SkXfermode::kSrc_Mode);
    486     rastBuilder->addLayer(p);
    487 }
    488 
    489 static void r1(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p)
    490 {
    491     rastBuilder->addLayer(p);
    492 
    493     p.setAlpha(0x40);
    494     p.setXfermodeMode(SkXfermode::kSrc_Mode);
    495     p.setStyle(SkPaint::kStroke_Style);
    496     p.setStrokeWidth(SK_Scalar1*2);
    497     rastBuilder->addLayer(p);
    498 }
    499 
    500 static void r2(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p)
    501 {
    502     p.setStyle(SkPaint::kStrokeAndFill_Style);
    503     p.setStrokeWidth(SK_Scalar1*4);
    504     rastBuilder->addLayer(p);
    505 
    506     p.setStyle(SkPaint::kStroke_Style);
    507     p.setStrokeWidth(SK_Scalar1*3/2);
    508     p.setXfermodeMode(SkXfermode::kClear_Mode);
    509     rastBuilder->addLayer(p);
    510 }
    511 
    512 static void r3(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p)
    513 {
    514     p.setStyle(SkPaint::kStroke_Style);
    515     p.setStrokeWidth(SK_Scalar1*3);
    516     rastBuilder->addLayer(p);
    517 
    518     p.setAlpha(0x20);
    519     p.setStyle(SkPaint::kFill_Style);
    520     p.setXfermodeMode(SkXfermode::kSrc_Mode);
    521     rastBuilder->addLayer(p);
    522 }
    523 
    524 static void r4(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p)
    525 {
    526     p.setAlpha(0x60);
    527     rastBuilder->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
    528 
    529     p.setAlpha(0xFF);
    530     p.setXfermodeMode(SkXfermode::kClear_Mode);
    531     rastBuilder->addLayer(p, SK_Scalar1*3/2, SK_Scalar1*3/2);
    532 
    533     p.setXfermode(nullptr);
    534     rastBuilder->addLayer(p);
    535 }
    536 
    537 #include "SkDiscretePathEffect.h"
    538 
    539 static void r5(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p)
    540 {
    541     rastBuilder->addLayer(p);
    542 
    543     p.setPathEffect(SkDiscretePathEffect::Create(SK_Scalar1*4, SK_Scalar1*3))->unref();
    544     p.setXfermodeMode(SkXfermode::kSrcOut_Mode);
    545     rastBuilder->addLayer(p);
    546 }
    547 
    548 static void r6(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p)
    549 {
    550     rastBuilder->addLayer(p);
    551 
    552     p.setAntiAlias(false);
    553     SkLayerRasterizer::Builder rastBuilder2;
    554     r5(&rastBuilder2, p);
    555     p.setRasterizer(rastBuilder2.detachRasterizer())->unref();
    556     p.setXfermodeMode(SkXfermode::kClear_Mode);
    557     rastBuilder->addLayer(p);
    558 }
    559 
    560 #include "Sk2DPathEffect.h"
    561 
    562 static SkPathEffect* MakeDotEffect(SkScalar radius, const SkMatrix& matrix) {
    563     SkPath path;
    564     path.addCircle(0, 0, radius);
    565     return SkPath2DPathEffect::Create(matrix, path);
    566 }
    567 
    568 static void r7(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p)
    569 {
    570     SkMatrix    lattice;
    571     lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
    572     lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
    573     p.setPathEffect(MakeDotEffect(SK_Scalar1*4, lattice))->unref();
    574     rastBuilder->addLayer(p);
    575 }
    576 
    577 static void r8(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p)
    578 {
    579     rastBuilder->addLayer(p);
    580 
    581     SkMatrix    lattice;
    582     lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
    583     lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
    584     p.setPathEffect(MakeDotEffect(SK_Scalar1*2, lattice))->unref();
    585     p.setXfermodeMode(SkXfermode::kClear_Mode);
    586     rastBuilder->addLayer(p);
    587 
    588     p.setPathEffect(nullptr);
    589     p.setXfermode(nullptr);
    590     p.setStyle(SkPaint::kStroke_Style);
    591     p.setStrokeWidth(SK_Scalar1);
    592     rastBuilder->addLayer(p);
    593 }
    594 
    595 static void r9(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p)
    596 {
    597     rastBuilder->addLayer(p);
    598 
    599     SkMatrix    lattice;
    600     lattice.setScale(SK_Scalar1, SK_Scalar1*6, 0, 0);
    601     lattice.postRotate(SkIntToScalar(30), 0, 0);
    602     p.setPathEffect(SkLine2DPathEffect::Create(SK_Scalar1*2, lattice))->unref();
    603     p.setXfermodeMode(SkXfermode::kClear_Mode);
    604     rastBuilder->addLayer(p);
    605 
    606     p.setPathEffect(nullptr);
    607     p.setXfermode(nullptr);
    608     p.setStyle(SkPaint::kStroke_Style);
    609     p.setStrokeWidth(SK_Scalar1);
    610     rastBuilder->addLayer(p);
    611 }
    612 
    613 typedef void (*raster_proc)(SkLayerRasterizer::Builder*, SkPaint&);
    614 
    615 static const raster_proc gRastProcs[] = {
    616     r0, r1, r2, r3, r4, r5, r6, r7, r8, r9
    617 };
    618 
    619 static void apply_shader(SkPaint* paint, int index) {
    620     raster_proc proc = gRastProcs[index];
    621     SkPaint p;
    622     SkLayerRasterizer::Builder rastBuilder;
    623 
    624     p.setAntiAlias(true);
    625     proc(&rastBuilder, p);
    626     paint->setRasterizer(rastBuilder.detachRasterizer())->unref();
    627     paint->setColor(SK_ColorBLUE);
    628 }
    629 
    630 #include "SkTypeface.h"
    631 
    632 static void texteffect_slide(SkCanvas* canvas) {
    633     const char* str = "Google";
    634     size_t len = strlen(str);
    635     SkScalar x = 20;
    636     SkScalar y = 80;
    637     SkPaint paint;
    638     paint.setTypeface(SkTypeface::CreateFromName("Georgia", SkTypeface::kItalic));
    639     paint.setTextSize(75);
    640     paint.setAntiAlias(true);
    641     paint.setColor(SK_ColorBLUE);
    642     for (size_t i = 0; i < SK_ARRAY_COUNT(gRastProcs); i++) {
    643         apply_shader(&paint, (int)i);
    644         canvas->drawText(str, len, x, y, paint);
    645         y += 80;
    646         if (i == 4) {
    647             x += 320;
    648             y = 80;
    649         }
    650     }
    651 }
    652 
    653 ///////////////////////////////////////////////////////////////////////////////
    654 
    655 #include "SkImageEncoder.h"
    656 
    657 static const SlideProc gProc[] = {
    658     patheffect_slide,
    659     gradient_slide,
    660     textonpath_slide,
    661     mesh_slide,
    662     texteffect_slide
    663 };
    664 
    665 class SlideView : public SampleView {
    666     int fIndex;
    667     bool fOnce;
    668 public:
    669     SlideView() {
    670         fOnce = false;
    671     }
    672 
    673     void init() {
    674         if (fOnce) {
    675             return;
    676         }
    677         fOnce = true;
    678 
    679         fIndex = 0;
    680 
    681         SkBitmap bm;
    682         bm.allocN32Pixels(1024, 768);
    683         SkCanvas canvas(bm);
    684         SkScalar s = SkIntToScalar(1024) / 640;
    685         canvas.scale(s, s);
    686         for (size_t i = 0; i < SK_ARRAY_COUNT(gProc); i++) {
    687             canvas.save();
    688             canvas.drawColor(BG_COLOR);
    689             gProc[i](&canvas);
    690             canvas.restore();
    691             SkString str;
    692             str.printf("/skimages/slide_" SK_SIZE_T_SPECIFIER ".png", i);
    693             SkImageEncoder::EncodeFile(str.c_str(), bm, SkImageEncoder::kPNG_Type, 100);
    694         }
    695         this->setBGColor(BG_COLOR);
    696     }
    697 
    698 protected:
    699     // overrides from SkEventSink
    700     bool onQuery(SkEvent* evt) override {
    701         if (SampleCode::TitleQ(*evt)) {
    702             SampleCode::TitleR(evt, "Slides");
    703             return true;
    704         }
    705         return this->INHERITED::onQuery(evt);
    706     }
    707 
    708     void onDrawContent(SkCanvas* canvas) override {
    709         this->init();
    710         gProc[fIndex](canvas);
    711     }
    712 
    713     SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned) override {
    714         this->init();
    715         fIndex = (fIndex + 1) % SK_ARRAY_COUNT(gProc);
    716         this->inval(nullptr);
    717         return nullptr;
    718     }
    719 
    720 private:
    721     typedef SampleView INHERITED;
    722 };
    723 
    724 //////////////////////////////////////////////////////////////////////////////
    725 
    726 static SkView* MyFactory() { return new SlideView; }
    727 static SkViewRegister reg(MyFactory);
    728