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