blob: 48153effa76efa96d8105b64fdfc5487a05034d2 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SampleCode.h"
9#include "SkView.h"
10#include "SkCanvas.h"
11#include "SkGradientShader.h"
12#include "SkPath.h"
13#include "SkRegion.h"
14#include "SkShader.h"
15#include "SkUtils.h"
16#include "SkImageDecoder.h"
17
reed@android.comf2b98d62010-12-20 18:26:13 +000018#ifdef SK_BUILD_FOR_WIN
19// windows doesn't have roundf
20inline float roundf(float x) { return (x-floor(x))>0.5 ? ceil(x) : floor(x); }
21#endif
22
reed@android.com8a1c16f2008-12-17 15:59:43 +000023#ifdef SK_DEBUG
24static void make_rgn(SkRegion* rgn, int left, int top, int right, int bottom,
25 size_t count, int32_t runs[]) {
26 SkIRect r;
27 r.set(left, top, right, bottom);
28
29 rgn->debugSetRuns(runs, count);
30 SkASSERT(rgn->getBounds() == r);
31}
32
33static void test_union_bug_1505668(SkRegion* ra, SkRegion* rb, SkRegion* rc) {
34 static int32_t dataA[] = {
35 0x00000001, 0x000001dd,
36 0x00000001, 0x0000000c, 0x0000000d, 0x00000025,
37 0x7fffffff, 0x000001de, 0x00000001, 0x00000025,
38 0x7fffffff, 0x000004b3, 0x00000001, 0x00000026,
39 0x7fffffff, 0x000004b4, 0x0000000c, 0x00000026,
40 0x7fffffff, 0x00000579, 0x00000000, 0x0000013a,
41 0x7fffffff, 0x000005d8, 0x00000000, 0x0000013b,
42 0x7fffffff, 0x7fffffff
43 };
44 make_rgn(ra, 0, 1, 315, 1496, SK_ARRAY_COUNT(dataA), dataA);
45
46 static int32_t dataB[] = {
47 0x000000b6, 0x000000c4,
48 0x000000a1, 0x000000f0, 0x7fffffff, 0x000000d6,
49 0x7fffffff, 0x000000e4, 0x00000070, 0x00000079,
50 0x000000a1, 0x000000b0, 0x7fffffff, 0x000000e6,
51 0x7fffffff, 0x000000f4, 0x00000070, 0x00000079,
52 0x000000a1, 0x000000b0, 0x7fffffff, 0x000000f6,
53 0x7fffffff, 0x00000104, 0x000000a1, 0x000000b0,
54 0x7fffffff, 0x7fffffff
55 };
56 make_rgn(rb, 112, 182, 240, 260, SK_ARRAY_COUNT(dataB), dataB);
57
58 rc->op(*ra, *rb, SkRegion::kUnion_Op);
59}
60#endif
61
reed@android.comf76bacf2009-05-13 14:00:33 +000062static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
63 dst->fLeft = (int)::roundf(src.fLeft * scale);
64 dst->fTop = (int)::roundf(src.fTop * scale);
65 dst->fRight = (int)::roundf(src.fRight * scale);
66 dst->fBottom = (int)::roundf(src.fBottom * scale);
67}
68
69static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
70 SkRegion tmp;
71 SkRegion::Iterator iter(src);
72
73 for (; !iter.done(); iter.next()) {
74 SkIRect r;
75 scale_rect(&r, iter.rect(), scale);
76 tmp.op(r, SkRegion::kUnion_Op);
77 }
78 dst->swap(tmp);
79}
80
81static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn,
82 const SkPaint& paint) {
83 SkRegion scaled;
84 scale_rgn(&scaled, rgn, 0.5f);
reed@android.com8a1c16f2008-12-17 15:59:43 +000085
reed@android.comf76bacf2009-05-13 14:00:33 +000086 SkRegion::Iterator iter(rgn);
87
reed@android.com8a1c16f2008-12-17 15:59:43 +000088 for (; !iter.done(); iter.next())
89 {
90 SkRect r;
91 r.set(iter.rect());
92 canvas->drawRect(r, paint);
93 }
94}
95
mike@reedtribe.org5fd92432011-05-05 01:59:48 +000096class RegionView : public SampleView {
reed@android.com8a1c16f2008-12-17 15:59:43 +000097public:
mike@reedtribe.org5fd92432011-05-05 01:59:48 +000098 RegionView() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000099 fBase.set(100, 100, 150, 150);
100 fRect = fBase;
101 fRect.inset(5, 5);
102 fRect.offset(25, 25);
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000103 this->setBGColor(0xFFDDDDDD);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000104 }
105
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000106 void build_rgn(SkRegion* rgn, SkRegion::Op op) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000107 rgn->setRect(fBase);
108 SkIRect r = fBase;
109 r.offset(75, 20);
110 rgn->op(r, SkRegion::kUnion_Op);
111 rgn->op(fRect, op);
112 }
113
114
115protected:
116 // overrides from SkEventSink
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000117 virtual bool onQuery(SkEvent* evt) {
118 if (SampleCode::TitleQ(*evt)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000119 SampleCode::TitleR(evt, "Regions");
120 return true;
121 }
122 return this->INHERITED::onQuery(evt);
123 }
124
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000125 void drawOrig(SkCanvas* canvas, bool bg) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126 SkRect r;
127 SkPaint paint;
128
129 paint.setStyle(SkPaint::kStroke_Style);
130 if (bg)
131 paint.setColor(0xFFBBBBBB);
132
133 r.set(fBase);
134 canvas->drawRect(r, paint);
135 r.set(fRect);
136 canvas->drawRect(r, paint);
137 }
138
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000139 void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000140 SkRegion rgn;
141
142 this->build_rgn(&rgn, op);
143
144 {
145 SkRegion tmp, tmp2(rgn);
146
147 tmp = tmp2;
148 tmp.translate(5, -3);
149
150 {
151 char buffer[1000];
152 size_t size = tmp.flatten(NULL);
153 SkASSERT(size <= sizeof(buffer));
154 size_t size2 = tmp.flatten(buffer);
155 SkASSERT(size == size2);
156
157 SkRegion tmp3;
158 size2 = tmp3.unflatten(buffer);
159 SkASSERT(size == size2);
160
161 SkASSERT(tmp3 == tmp);
162 }
163
164 rgn.translate(20, 30, &tmp);
165 SkASSERT(rgn.isEmpty() || tmp != rgn);
166 tmp.translate(-20, -30);
167 SkASSERT(tmp == rgn);
168 }
169
170 this->drawOrig(canvas, true);
171
172 SkPaint paint;
173 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
174 paint_rgn(canvas, rgn, paint);
175
176 paint.setStyle(SkPaint::kStroke_Style);
177 paint.setColor(color);
178 paint_rgn(canvas, rgn, paint);
179 }
180
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000181 void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182 SkRegion rgn;
183 SkPath path;
184
185 this->build_rgn(&rgn, op);
186 rgn.getBoundaryPath(&path);
187
188 this->drawOrig(canvas, true);
189
190 SkPaint paint;
191
192 paint.setStyle(SkPaint::kFill_Style);
193 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
194 canvas->drawPath(path, paint);
195 paint.setColor(color);
196 paint.setStyle(SkPaint::kStroke_Style);
197 canvas->drawPath(path, paint);
198 }
199
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000200 virtual void onDrawContent(SkCanvas* canvas) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201#ifdef SK_DEBUG
202 if (true) {
203 SkRegion a, b, c;
204 test_union_bug_1505668(&a, &b, &c);
205
206 if (false) { // draw the result of the test
207 SkPaint paint;
208
209 canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
210 paint.setColor(SK_ColorRED);
211 paint_rgn(canvas, a, paint);
212 paint.setColor(0x800000FF);
213 paint_rgn(canvas, b, paint);
214 paint.setColor(SK_ColorBLACK);
215 paint.setStyle(SkPaint::kStroke_Style);
216 // paint_rgn(canvas, c, paint);
217 return;
218 }
219 }
220#endif
221
222 static const struct {
223 SkColor fColor;
224 const char* fName;
225 SkRegion::Op fOp;
226 } gOps[] = {
227 { SK_ColorBLACK, "Difference", SkRegion::kDifference_Op },
228 { SK_ColorRED, "Intersect", SkRegion::kIntersect_Op },
229 { 0xFF008800, "Union", SkRegion::kUnion_Op },
230 { SK_ColorBLUE, "XOR", SkRegion::kXOR_Op }
231 };
232
233 SkPaint textPaint;
234 textPaint.setAntiAlias(true);
235 textPaint.setTextSize(SK_Scalar1*24);
236
237 this->drawOrig(canvas, false);
238 canvas->save();
239 canvas->translate(SkIntToScalar(200), 0);
240 this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK);
241 canvas->restore();
242
243 canvas->translate(0, SkIntToScalar(200));
244
senorblanco@chromium.org64cc5792011-05-19 19:58:58 +0000245 for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); op++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246 canvas->drawText(gOps[op].fName, strlen(gOps[op].fName), SkIntToScalar(75), SkIntToScalar(50), textPaint);
247
248 this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
249
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000250 canvas->save();
251 canvas->translate(0, SkIntToScalar(200));
252 this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
253 canvas->restore();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254
255 canvas->translate(SkIntToScalar(200), 0);
256 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257 }
258
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000259 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
reed@android.com671cd652009-05-22 20:44:12 +0000260 return fRect.contains(SkScalarRound(x), SkScalarRound(y)) ? new Click(this) : NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000261 }
262
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000263 virtual bool onClick(Click* click) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000264 fRect.offset(click->fICurr.fX - click->fIPrev.fX,
265 click->fICurr.fY - click->fIPrev.fY);
reed@android.com671cd652009-05-22 20:44:12 +0000266 this->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267 return true;
268 }
269
270private:
271 SkIRect fBase, fRect;
272
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000273 typedef SampleView INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000274};
275
276//////////////////////////////////////////////////////////////////////////////
277
278static SkView* MyFactory() { return new RegionView; }
279static SkViewRegister reg(MyFactory);
280