blob: fef44f53cef1a980882e5e932531ab9b61d62462 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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 */
reed@google.combf0001d2014-01-13 14:53:55 +00007
reed@android.com88983632009-03-23 16:05:19 +00008#include "SampleCode.h"
reed76113a92015-02-02 12:55:02 -08009#include "SkAnimTimer.h"
reed@android.com88983632009-03-23 16:05:19 +000010#include "SkView.h"
11#include "SkCanvas.h"
reed@android.com88983632009-03-23 16:05:19 +000012#include "SkCornerPathEffect.h"
13#include "SkGradientShader.h"
14#include "SkGraphics.h"
reed@android.com88983632009-03-23 16:05:19 +000015#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"
reed@android.com88983632009-03-23 16:05:19 +000027#include "SkColorPriv.h"
reed@android.com88983632009-03-23 16:05:19 +000028
29static SkRandom gRand;
30
reed@android.com88983632009-03-23 16:05:19 +000031static void generate_pts(SkPoint pts[], int count, int w, int h) {
32 for (int i = 0; i < count; i++) {
33 pts[i].set(gRand.nextUScalar1() * 3 * w - SkIntToScalar(w),
34 gRand.nextUScalar1() * 3 * h - SkIntToScalar(h));
35 }
36}
37
38static bool check_zeros(const SkPMColor pixels[], int count, int skip) {
39 for (int i = 0; i < count; i++) {
40 if (*pixels) {
41 return false;
42 }
43 pixels += skip;
44 }
45 return true;
46}
47
48static bool check_bitmap_margin(const SkBitmap& bm, int margin) {
49 size_t rb = bm.rowBytes();
50 for (int i = 0; i < margin; i++) {
51 if (!check_zeros(bm.getAddr32(0, i), bm.width(), 1)) {
52 return false;
53 }
54 int bottom = bm.height() - i - 1;
55 if (!check_zeros(bm.getAddr32(0, bottom), bm.width(), 1)) {
56 return false;
57 }
58 // left column
reed@google.com7fa2a652014-01-27 13:42:58 +000059 if (!check_zeros(bm.getAddr32(i, 0), bm.height(), SkToInt(rb >> 2))) {
reed@android.com88983632009-03-23 16:05:19 +000060 return false;
61 }
62 int right = bm.width() - margin + i;
reed@google.com7fa2a652014-01-27 13:42:58 +000063 if (!check_zeros(bm.getAddr32(right, 0), bm.height(),
64 SkToInt(rb >> 2))) {
reed@android.com88983632009-03-23 16:05:19 +000065 return false;
66 }
67 }
68 return true;
69}
70
reed@android.com28937282009-08-28 15:34:46 +000071#define WIDTH 620
72#define HEIGHT 460
73#define MARGIN 10
74
75static void line_proc(SkCanvas* canvas, const SkPaint& paint,
76 const SkBitmap& bm) {
77 const int N = 2;
78 SkPoint pts[N];
79 for (int i = 0; i < 400; i++) {
80 generate_pts(pts, N, WIDTH, HEIGHT);
81
82 canvas->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
83 if (!check_bitmap_margin(bm, MARGIN)) {
84 SkDebugf("---- hairline failure (%g %g) (%g %g)\n",
85 pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY);
86 break;
87 }
88 }
89}
90
91static void poly_proc(SkCanvas* canvas, const SkPaint& paint,
92 const SkBitmap& bm) {
93 const int N = 8;
94 SkPoint pts[N];
95 for (int i = 0; i < 50; i++) {
96 generate_pts(pts, N, WIDTH, HEIGHT);
rmistry@google.comae933ce2012-08-23 18:19:56 +000097
reed@android.com28937282009-08-28 15:34:46 +000098 SkPath path;
99 path.moveTo(pts[0]);
100 for (int j = 1; j < N; j++) {
101 path.lineTo(pts[j]);
102 }
103 canvas->drawPath(path, paint);
104 }
105}
106
107static SkPoint ave(const SkPoint& a, const SkPoint& b) {
108 SkPoint c = a + b;
109 c.fX = SkScalarHalf(c.fX);
110 c.fY = SkScalarHalf(c.fY);
111 return c;
112}
113
114static void quad_proc(SkCanvas* canvas, const SkPaint& paint,
115 const SkBitmap& bm) {
116 const int N = 30;
117 SkPoint pts[N];
118 for (int i = 0; i < 10; i++) {
119 generate_pts(pts, N, WIDTH, HEIGHT);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000120
reed@android.com28937282009-08-28 15:34:46 +0000121 SkPath path;
122 path.moveTo(pts[0]);
123 for (int j = 1; j < N - 2; j++) {
124 path.quadTo(pts[j], ave(pts[j], pts[j+1]));
125 }
126 path.quadTo(pts[N - 2], pts[N - 1]);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000127
reed@android.com28937282009-08-28 15:34:46 +0000128 canvas->drawPath(path, paint);
129 }
130}
131
132static void add_cubic(SkPath* path, const SkPoint& mid, const SkPoint& end) {
133 SkPoint start;
134 path->getLastPt(&start);
135 path->cubicTo(ave(start, mid), ave(mid, end), end);
136}
137
138static void cube_proc(SkCanvas* canvas, const SkPaint& paint,
139 const SkBitmap& bm) {
140 const int N = 30;
141 SkPoint pts[N];
142 for (int i = 0; i < 10; i++) {
143 generate_pts(pts, N, WIDTH, HEIGHT);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000144
reed@android.com28937282009-08-28 15:34:46 +0000145 SkPath path;
146 path.moveTo(pts[0]);
147 for (int j = 1; j < N - 2; j++) {
148 add_cubic(&path, pts[j], ave(pts[j], pts[j+1]));
149 }
150 add_cubic(&path, pts[N - 2], pts[N - 1]);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000151
reed@android.com28937282009-08-28 15:34:46 +0000152 canvas->drawPath(path, paint);
153 }
154}
155
156typedef void (*HairProc)(SkCanvas*, const SkPaint&, const SkBitmap&);
157
158static const struct {
159 const char* fName;
160 HairProc fProc;
161} gProcs[] = {
162 { "line", line_proc },
163 { "poly", poly_proc },
164 { "quad", quad_proc },
165 { "cube", cube_proc },
166};
167
168static int cycle_hairproc_index(int index) {
169 return (index + 1) % SK_ARRAY_COUNT(gProcs);
170}
reed@android.com88983632009-03-23 16:05:19 +0000171
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000172class HairlineView : public SampleView {
reed@android.coma3d90102009-11-30 12:48:33 +0000173 SkMSec fNow;
reed@android.com28937282009-08-28 15:34:46 +0000174 int fProcIndex;
175 bool fDoAA;
reed@android.com88983632009-03-23 16:05:19 +0000176public:
rmistry@google.comae933ce2012-08-23 18:19:56 +0000177 HairlineView() {
reed@android.com28937282009-08-28 15:34:46 +0000178 fProcIndex = 0;
179 fDoAA = true;
reed@android.coma3d90102009-11-30 12:48:33 +0000180 fNow = 0;
reed@android.com28937282009-08-28 15:34:46 +0000181 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000182
reed@android.com88983632009-03-23 16:05:19 +0000183protected:
184 // overrides from SkEventSink
mtklein36352bf2015-03-25 18:17:31 -0700185 bool onQuery(SkEvent* evt) override {
reed@android.com88983632009-03-23 16:05:19 +0000186 if (SampleCode::TitleQ(*evt)) {
reed@android.com28937282009-08-28 15:34:46 +0000187 SkString str;
188 str.printf("Hair-%s", gProcs[fProcIndex].fName);
189 SampleCode::TitleR(evt, str.c_str());
reed@android.com88983632009-03-23 16:05:19 +0000190 return true;
191 }
192 return this->INHERITED::onQuery(evt);
193 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000194
reed@android.com88983632009-03-23 16:05:19 +0000195 void show_bitmaps(SkCanvas* canvas, const SkBitmap& b0, const SkBitmap& b1,
196 const SkIRect& inset) {
halcanary96fcdcc2015-08-27 07:41:13 -0700197 canvas->drawBitmap(b0, 0, 0, nullptr);
198 canvas->drawBitmap(b1, SkIntToScalar(b0.width()), 0, nullptr);
reed@android.com88983632009-03-23 16:05:19 +0000199 }
200
mtklein36352bf2015-03-25 18:17:31 -0700201 void onDrawContent(SkCanvas* canvas) override {
reed@android.coma3d90102009-11-30 12:48:33 +0000202 gRand.setSeed(fNow);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000203
reed@android.com88983632009-03-23 16:05:19 +0000204 SkBitmap bm, bm2;
commit-bot@chromium.orga8c18312014-02-17 02:55:57 +0000205 bm.allocN32Pixels(WIDTH + MARGIN*2, HEIGHT + MARGIN*2);
reed@android.com88983632009-03-23 16:05:19 +0000206 // this will erase our margin, which we want to always stay 0
junov@google.comdbfac8a2012-12-06 21:47:40 +0000207 bm.eraseColor(SK_ColorTRANSPARENT);
reed@android.com88983632009-03-23 16:05:19 +0000208
commit-bot@chromium.orga8c18312014-02-17 02:55:57 +0000209 bm2.installPixels(SkImageInfo::MakeN32Premul(WIDTH, HEIGHT),
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +0000210 bm.getAddr32(MARGIN, MARGIN), bm.rowBytes());
rmistry@google.comae933ce2012-08-23 18:19:56 +0000211
reed@android.com88983632009-03-23 16:05:19 +0000212 SkCanvas c2(bm2);
213 SkPaint paint;
reed@android.com28937282009-08-28 15:34:46 +0000214 paint.setAntiAlias(fDoAA);
215 paint.setStyle(SkPaint::kStroke_Style);
216
junov@google.comdbfac8a2012-12-06 21:47:40 +0000217 bm2.eraseColor(SK_ColorTRANSPARENT);
reed@android.com28937282009-08-28 15:34:46 +0000218 gProcs[fProcIndex].fProc(&c2, paint, bm);
halcanary96fcdcc2015-08-27 07:41:13 -0700219 canvas->drawBitmap(bm2, SkIntToScalar(10), SkIntToScalar(10), nullptr);
reed@android.com88983632009-03-23 16:05:19 +0000220 }
221
mtklein36352bf2015-03-25 18:17:31 -0700222 bool onAnimate(const SkAnimTimer&) override {
reedd9adfe62015-02-01 19:01:04 -0800223 if (fDoAA) {
224 fProcIndex = cycle_hairproc_index(fProcIndex);
225 // todo: signal that we want to rebuild our TITLE
226 }
227 fDoAA = !fDoAA;
228 return true;
229 }
230
mtklein36352bf2015-03-25 18:17:31 -0700231 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
reed@android.com28937282009-08-28 15:34:46 +0000232 fDoAA = !fDoAA;
halcanary96fcdcc2015-08-27 07:41:13 -0700233 this->inval(nullptr);
reed@google.com4d5c26d2013-01-08 16:17:50 +0000234 return this->INHERITED::onFindClickHandler(x, y, modi);
reed@android.com28937282009-08-28 15:34:46 +0000235 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000236
reed@android.com28937282009-08-28 15:34:46 +0000237
reed@android.com88983632009-03-23 16:05:19 +0000238private:
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000239 typedef SampleView INHERITED;
reed@android.com88983632009-03-23 16:05:19 +0000240};
241
242//////////////////////////////////////////////////////////////////////////////
243
244static SkView* MyFactory() { return new HairlineView; }
245static SkViewRegister reg(MyFactory);