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