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