Home | History | Annotate | Download | only in samplecode
      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 "SkCornerPathEffect.h"
     12 #include "SkGradientShader.h"
     13 #include "SkGraphics.h"
     14 #include "SkImageDecoder.h"
     15 #include "SkPath.h"
     16 #include "SkRandom.h"
     17 #include "SkRegion.h"
     18 #include "SkShader.h"
     19 #include "SkUtils.h"
     20 #include "SkColorPriv.h"
     21 #include "SkColorFilter.h"
     22 #include "SkTime.h"
     23 #include "SkTypeface.h"
     24 #include "SkXfermode.h"
     25 
     26 #include "SkStream.h"
     27 #include "SkXMLParser.h"
     28 #include "SkColorPriv.h"
     29 #include "SkImageDecoder.h"
     30 
     31 static SkRandom gRand;
     32 
     33 static void test_chromium_9005() {
     34     SkBitmap bm;
     35     bm.allocN32Pixels(800, 600);
     36 
     37     SkCanvas canvas(bm);
     38 
     39     SkPoint pt0 = { 799.33374f, 1.2360189f };
     40     SkPoint pt1 = { 808.49969f, -7.4338055f };
     41 
     42     SkPaint paint;
     43     paint.setAntiAlias(true);
     44     canvas.drawLine(pt0.fX, pt0.fY, pt1.fX, pt1.fY, paint);
     45 }
     46 
     47 static void generate_pts(SkPoint pts[], int count, int w, int h) {
     48     for (int i = 0; i < count; i++) {
     49         pts[i].set(gRand.nextUScalar1() * 3 * w - SkIntToScalar(w),
     50                    gRand.nextUScalar1() * 3 * h - SkIntToScalar(h));
     51     }
     52 }
     53 
     54 static bool check_zeros(const SkPMColor pixels[], int count, int skip) {
     55     for (int i = 0; i < count; i++) {
     56         if (*pixels) {
     57             return false;
     58         }
     59         pixels += skip;
     60     }
     61     return true;
     62 }
     63 
     64 static bool check_bitmap_margin(const SkBitmap& bm, int margin) {
     65     size_t rb = bm.rowBytes();
     66     for (int i = 0; i < margin; i++) {
     67         if (!check_zeros(bm.getAddr32(0, i), bm.width(), 1)) {
     68             return false;
     69         }
     70         int bottom = bm.height() - i - 1;
     71         if (!check_zeros(bm.getAddr32(0, bottom), bm.width(), 1)) {
     72             return false;
     73         }
     74         // left column
     75         if (!check_zeros(bm.getAddr32(i, 0), bm.height(), SkToInt(rb >> 2))) {
     76             return false;
     77         }
     78         int right = bm.width() - margin + i;
     79         if (!check_zeros(bm.getAddr32(right, 0), bm.height(),
     80                          SkToInt(rb >> 2))) {
     81             return false;
     82         }
     83     }
     84     return true;
     85 }
     86 
     87 #define WIDTH   620
     88 #define HEIGHT  460
     89 #define MARGIN  10
     90 
     91 static void line_proc(SkCanvas* canvas, const SkPaint& paint,
     92                       const SkBitmap& bm) {
     93     const int N = 2;
     94     SkPoint pts[N];
     95     for (int i = 0; i < 400; i++) {
     96         generate_pts(pts, N, WIDTH, HEIGHT);
     97 
     98         canvas->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
     99         if (!check_bitmap_margin(bm, MARGIN)) {
    100             SkDebugf("---- hairline failure (%g %g) (%g %g)\n",
    101                      pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY);
    102             break;
    103         }
    104     }
    105 }
    106 
    107 static void poly_proc(SkCanvas* canvas, const SkPaint& paint,
    108                       const SkBitmap& bm) {
    109     const int N = 8;
    110     SkPoint pts[N];
    111     for (int i = 0; i < 50; i++) {
    112         generate_pts(pts, N, WIDTH, HEIGHT);
    113 
    114         SkPath path;
    115         path.moveTo(pts[0]);
    116         for (int j = 1; j < N; j++) {
    117             path.lineTo(pts[j]);
    118         }
    119         canvas->drawPath(path, paint);
    120     }
    121 }
    122 
    123 static SkPoint ave(const SkPoint& a, const SkPoint& b) {
    124     SkPoint c = a + b;
    125     c.fX = SkScalarHalf(c.fX);
    126     c.fY = SkScalarHalf(c.fY);
    127     return c;
    128 }
    129 
    130 static void quad_proc(SkCanvas* canvas, const SkPaint& paint,
    131                       const SkBitmap& bm) {
    132     const int N = 30;
    133     SkPoint pts[N];
    134     for (int i = 0; i < 10; i++) {
    135         generate_pts(pts, N, WIDTH, HEIGHT);
    136 
    137         SkPath path;
    138         path.moveTo(pts[0]);
    139         for (int j = 1; j < N - 2; j++) {
    140             path.quadTo(pts[j], ave(pts[j], pts[j+1]));
    141         }
    142         path.quadTo(pts[N - 2], pts[N - 1]);
    143 
    144         canvas->drawPath(path, paint);
    145     }
    146 }
    147 
    148 static void add_cubic(SkPath* path, const SkPoint& mid, const SkPoint& end) {
    149     SkPoint start;
    150     path->getLastPt(&start);
    151     path->cubicTo(ave(start, mid), ave(mid, end), end);
    152 }
    153 
    154 static void cube_proc(SkCanvas* canvas, const SkPaint& paint,
    155                       const SkBitmap& bm) {
    156     const int N = 30;
    157     SkPoint pts[N];
    158     for (int i = 0; i < 10; i++) {
    159         generate_pts(pts, N, WIDTH, HEIGHT);
    160 
    161         SkPath path;
    162         path.moveTo(pts[0]);
    163         for (int j = 1; j < N - 2; j++) {
    164             add_cubic(&path, pts[j], ave(pts[j], pts[j+1]));
    165         }
    166         add_cubic(&path, pts[N - 2], pts[N - 1]);
    167 
    168         canvas->drawPath(path, paint);
    169     }
    170 }
    171 
    172 typedef void (*HairProc)(SkCanvas*, const SkPaint&, const SkBitmap&);
    173 
    174 static const struct {
    175     const char* fName;
    176     HairProc    fProc;
    177 } gProcs[] = {
    178     { "line",   line_proc },
    179     { "poly",   poly_proc },
    180     { "quad",   quad_proc },
    181     { "cube",   cube_proc },
    182 };
    183 
    184 static int cycle_hairproc_index(int index) {
    185     return (index + 1) % SK_ARRAY_COUNT(gProcs);
    186 }
    187 
    188 class HairlineView : public SampleView {
    189     SkMSec fNow;
    190     int fProcIndex;
    191     bool fDoAA;
    192 public:
    193     HairlineView() {
    194         fCounter = 0;
    195         fProcIndex = 0;
    196         fDoAA = true;
    197         fNow = 0;
    198     }
    199 
    200 protected:
    201     // overrides from SkEventSink
    202     virtual bool onQuery(SkEvent* evt) {
    203         if (SampleCode::TitleQ(*evt)) {
    204             SkString str;
    205             str.printf("Hair-%s", gProcs[fProcIndex].fName);
    206             SampleCode::TitleR(evt, str.c_str());
    207             return true;
    208         }
    209         return this->INHERITED::onQuery(evt);
    210     }
    211 
    212     void show_bitmaps(SkCanvas* canvas, const SkBitmap& b0, const SkBitmap& b1,
    213                       const SkIRect& inset) {
    214         canvas->drawBitmap(b0, 0, 0, NULL);
    215         canvas->drawBitmap(b1, SkIntToScalar(b0.width()), 0, NULL);
    216     }
    217 
    218     int fCounter;
    219 
    220     virtual void onDrawContent(SkCanvas* canvas) {
    221         gRand.setSeed(fNow);
    222 
    223         if (false) { // avoid bit rot, suppress warning
    224             test_chromium_9005();
    225         }
    226 
    227         SkBitmap bm, bm2;
    228         bm.allocN32Pixels(WIDTH + MARGIN*2, HEIGHT + MARGIN*2);
    229         // this will erase our margin, which we want to always stay 0
    230         bm.eraseColor(SK_ColorTRANSPARENT);
    231 
    232         bm2.installPixels(SkImageInfo::MakeN32Premul(WIDTH, HEIGHT),
    233                           bm.getAddr32(MARGIN, MARGIN), bm.rowBytes());
    234 
    235         SkCanvas c2(bm2);
    236         SkPaint paint;
    237         paint.setAntiAlias(fDoAA);
    238         paint.setStyle(SkPaint::kStroke_Style);
    239 
    240         bm2.eraseColor(SK_ColorTRANSPARENT);
    241         gProcs[fProcIndex].fProc(&c2, paint, bm);
    242         canvas->drawBitmap(bm2, SkIntToScalar(10), SkIntToScalar(10), NULL);
    243 
    244         SkMSec now = SampleCode::GetAnimTime();
    245         if (fNow != now) {
    246             fNow = now;
    247             fCounter += 1;
    248             fDoAA = !fDoAA;
    249             if (fCounter > 50) {
    250                 fProcIndex = cycle_hairproc_index(fProcIndex);
    251                 // todo: signal that we want to rebuild our TITLE
    252                 fCounter = 0;
    253             }
    254             this->inval(NULL);
    255         }
    256     }
    257 
    258     virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y,
    259                                               unsigned modi) {
    260         fDoAA = !fDoAA;
    261         this->inval(NULL);
    262         return this->INHERITED::onFindClickHandler(x, y, modi);
    263     }
    264 
    265 
    266 private:
    267     typedef SampleView INHERITED;
    268 };
    269 
    270 //////////////////////////////////////////////////////////////////////////////
    271 
    272 static SkView* MyFactory() { return new HairlineView; }
    273 static SkViewRegister reg(MyFactory);
    274