blob: 3c254472fa735202fbf3041f7939018df016e316 [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"
9#include "SkView.h"
10#include "SkCanvas.h"
reed@android.com88983632009-03-23 16:05:19 +000011#include "SkCornerPathEffect.h"
12#include "SkGradientShader.h"
13#include "SkGraphics.h"
14#include "SkImageDecoder.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"
27#include "SkXMLParser.h"
28#include "SkColorPriv.h"
29#include "SkImageDecoder.h"
30
31static SkRandom gRand;
32
reed@android.com88983632009-03-23 16:05:19 +000033static void generate_pts(SkPoint pts[], int count, int w, int h) {
34 for (int i = 0; i < count; i++) {
35 pts[i].set(gRand.nextUScalar1() * 3 * w - SkIntToScalar(w),
36 gRand.nextUScalar1() * 3 * h - SkIntToScalar(h));
37 }
38}
39
40static bool check_zeros(const SkPMColor pixels[], int count, int skip) {
41 for (int i = 0; i < count; i++) {
42 if (*pixels) {
43 return false;
44 }
45 pixels += skip;
46 }
47 return true;
48}
49
50static bool check_bitmap_margin(const SkBitmap& bm, int margin) {
51 size_t rb = bm.rowBytes();
52 for (int i = 0; i < margin; i++) {
53 if (!check_zeros(bm.getAddr32(0, i), bm.width(), 1)) {
54 return false;
55 }
56 int bottom = bm.height() - i - 1;
57 if (!check_zeros(bm.getAddr32(0, bottom), bm.width(), 1)) {
58 return false;
59 }
60 // left column
reed@google.com7fa2a652014-01-27 13:42:58 +000061 if (!check_zeros(bm.getAddr32(i, 0), bm.height(), SkToInt(rb >> 2))) {
reed@android.com88983632009-03-23 16:05:19 +000062 return false;
63 }
64 int right = bm.width() - margin + i;
reed@google.com7fa2a652014-01-27 13:42:58 +000065 if (!check_zeros(bm.getAddr32(right, 0), bm.height(),
66 SkToInt(rb >> 2))) {
reed@android.com88983632009-03-23 16:05:19 +000067 return false;
68 }
69 }
70 return true;
71}
72
reed@android.com28937282009-08-28 15:34:46 +000073#define WIDTH 620
74#define HEIGHT 460
75#define MARGIN 10
76
77static void line_proc(SkCanvas* canvas, const SkPaint& paint,
78 const SkBitmap& bm) {
79 const int N = 2;
80 SkPoint pts[N];
81 for (int i = 0; i < 400; i++) {
82 generate_pts(pts, N, WIDTH, HEIGHT);
83
84 canvas->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
85 if (!check_bitmap_margin(bm, MARGIN)) {
86 SkDebugf("---- hairline failure (%g %g) (%g %g)\n",
87 pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY);
88 break;
89 }
90 }
91}
92
93static void poly_proc(SkCanvas* canvas, const SkPaint& paint,
94 const SkBitmap& bm) {
95 const int N = 8;
96 SkPoint pts[N];
97 for (int i = 0; i < 50; i++) {
98 generate_pts(pts, N, WIDTH, HEIGHT);
rmistry@google.comae933ce2012-08-23 18:19:56 +000099
reed@android.com28937282009-08-28 15:34:46 +0000100 SkPath path;
101 path.moveTo(pts[0]);
102 for (int j = 1; j < N; j++) {
103 path.lineTo(pts[j]);
104 }
105 canvas->drawPath(path, paint);
106 }
107}
108
109static SkPoint ave(const SkPoint& a, const SkPoint& b) {
110 SkPoint c = a + b;
111 c.fX = SkScalarHalf(c.fX);
112 c.fY = SkScalarHalf(c.fY);
113 return c;
114}
115
116static void quad_proc(SkCanvas* canvas, const SkPaint& paint,
117 const SkBitmap& bm) {
118 const int N = 30;
119 SkPoint pts[N];
120 for (int i = 0; i < 10; i++) {
121 generate_pts(pts, N, WIDTH, HEIGHT);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000122
reed@android.com28937282009-08-28 15:34:46 +0000123 SkPath path;
124 path.moveTo(pts[0]);
125 for (int j = 1; j < N - 2; j++) {
126 path.quadTo(pts[j], ave(pts[j], pts[j+1]));
127 }
128 path.quadTo(pts[N - 2], pts[N - 1]);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000129
reed@android.com28937282009-08-28 15:34:46 +0000130 canvas->drawPath(path, paint);
131 }
132}
133
134static void add_cubic(SkPath* path, const SkPoint& mid, const SkPoint& end) {
135 SkPoint start;
136 path->getLastPt(&start);
137 path->cubicTo(ave(start, mid), ave(mid, end), end);
138}
139
140static void cube_proc(SkCanvas* canvas, const SkPaint& paint,
141 const SkBitmap& bm) {
142 const int N = 30;
143 SkPoint pts[N];
144 for (int i = 0; i < 10; i++) {
145 generate_pts(pts, N, WIDTH, HEIGHT);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000146
reed@android.com28937282009-08-28 15:34:46 +0000147 SkPath path;
148 path.moveTo(pts[0]);
149 for (int j = 1; j < N - 2; j++) {
150 add_cubic(&path, pts[j], ave(pts[j], pts[j+1]));
151 }
152 add_cubic(&path, pts[N - 2], pts[N - 1]);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000153
reed@android.com28937282009-08-28 15:34:46 +0000154 canvas->drawPath(path, paint);
155 }
156}
157
158typedef void (*HairProc)(SkCanvas*, const SkPaint&, const SkBitmap&);
159
160static const struct {
161 const char* fName;
162 HairProc fProc;
163} gProcs[] = {
164 { "line", line_proc },
165 { "poly", poly_proc },
166 { "quad", quad_proc },
167 { "cube", cube_proc },
168};
169
170static int cycle_hairproc_index(int index) {
171 return (index + 1) % SK_ARRAY_COUNT(gProcs);
172}
reed@android.com88983632009-03-23 16:05:19 +0000173
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000174class HairlineView : public SampleView {
reed@android.coma3d90102009-11-30 12:48:33 +0000175 SkMSec fNow;
reed@android.com28937282009-08-28 15:34:46 +0000176 int fProcIndex;
177 bool fDoAA;
reed@android.com88983632009-03-23 16:05:19 +0000178public:
rmistry@google.comae933ce2012-08-23 18:19:56 +0000179 HairlineView() {
reed@android.com28937282009-08-28 15:34:46 +0000180 fProcIndex = 0;
181 fDoAA = true;
reed@android.coma3d90102009-11-30 12:48:33 +0000182 fNow = 0;
reed@android.com28937282009-08-28 15:34:46 +0000183 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000184
reed@android.com88983632009-03-23 16:05:19 +0000185protected:
186 // overrides from SkEventSink
reedd9adfe62015-02-01 19:01:04 -0800187 bool onQuery(SkEvent* evt) SK_OVERRIDE {
reed@android.com88983632009-03-23 16:05:19 +0000188 if (SampleCode::TitleQ(*evt)) {
reed@android.com28937282009-08-28 15:34:46 +0000189 SkString str;
190 str.printf("Hair-%s", gProcs[fProcIndex].fName);
191 SampleCode::TitleR(evt, str.c_str());
reed@android.com88983632009-03-23 16:05:19 +0000192 return true;
193 }
194 return this->INHERITED::onQuery(evt);
195 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000196
reed@android.com88983632009-03-23 16:05:19 +0000197 void show_bitmaps(SkCanvas* canvas, const SkBitmap& b0, const SkBitmap& b1,
198 const SkIRect& inset) {
199 canvas->drawBitmap(b0, 0, 0, NULL);
200 canvas->drawBitmap(b1, SkIntToScalar(b0.width()), 0, NULL);
201 }
202
reedd9adfe62015-02-01 19:01:04 -0800203 void onDrawContent(SkCanvas* canvas) SK_OVERRIDE {
reed@android.coma3d90102009-11-30 12:48:33 +0000204 gRand.setSeed(fNow);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000205
reed@android.com88983632009-03-23 16:05:19 +0000206 SkBitmap bm, bm2;
commit-bot@chromium.orga8c18312014-02-17 02:55:57 +0000207 bm.allocN32Pixels(WIDTH + MARGIN*2, HEIGHT + MARGIN*2);
reed@android.com88983632009-03-23 16:05:19 +0000208 // this will erase our margin, which we want to always stay 0
junov@google.comdbfac8a2012-12-06 21:47:40 +0000209 bm.eraseColor(SK_ColorTRANSPARENT);
reed@android.com88983632009-03-23 16:05:19 +0000210
commit-bot@chromium.orga8c18312014-02-17 02:55:57 +0000211 bm2.installPixels(SkImageInfo::MakeN32Premul(WIDTH, HEIGHT),
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +0000212 bm.getAddr32(MARGIN, MARGIN), bm.rowBytes());
rmistry@google.comae933ce2012-08-23 18:19:56 +0000213
reed@android.com88983632009-03-23 16:05:19 +0000214 SkCanvas c2(bm2);
215 SkPaint paint;
reed@android.com28937282009-08-28 15:34:46 +0000216 paint.setAntiAlias(fDoAA);
217 paint.setStyle(SkPaint::kStroke_Style);
218
junov@google.comdbfac8a2012-12-06 21:47:40 +0000219 bm2.eraseColor(SK_ColorTRANSPARENT);
reed@android.com28937282009-08-28 15:34:46 +0000220 gProcs[fProcIndex].fProc(&c2, paint, bm);
221 canvas->drawBitmap(bm2, SkIntToScalar(10), SkIntToScalar(10), NULL);
reed@android.com88983632009-03-23 16:05:19 +0000222 }
223
reedd9adfe62015-02-01 19:01:04 -0800224 bool onAnimatePulse(SkMSec curr, SkMSec prev) SK_OVERRIDE {
225 if (fDoAA) {
226 fProcIndex = cycle_hairproc_index(fProcIndex);
227 // todo: signal that we want to rebuild our TITLE
228 }
229 fDoAA = !fDoAA;
230 return true;
231 }
232
233 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) SK_OVERRIDE {
reed@android.com28937282009-08-28 15:34:46 +0000234 fDoAA = !fDoAA;
235 this->inval(NULL);
reed@google.com4d5c26d2013-01-08 16:17:50 +0000236 return this->INHERITED::onFindClickHandler(x, y, modi);
reed@android.com28937282009-08-28 15:34:46 +0000237 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000238
reed@android.com28937282009-08-28 15:34:46 +0000239
reed@android.com88983632009-03-23 16:05:19 +0000240private:
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000241 typedef SampleView INHERITED;
reed@android.com88983632009-03-23 16:05:19 +0000242};
243
244//////////////////////////////////////////////////////////////////////////////
245
246static SkView* MyFactory() { return new HairlineView; }
247static SkViewRegister reg(MyFactory);