blob: 272c722993574cc928e232ef8bc332e39bf3b43f [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001#include "SampleCode.h"
2#include "SkView.h"
3#include "SkCanvas.h"
4#include "SkGradientShader.h"
5#include "SkPath.h"
6#include "SkRegion.h"
7#include "SkShader.h"
8#include "SkUtils.h"
9#include "SkImageDecoder.h"
10
reed@android.comf2b98d62010-12-20 18:26:13 +000011#ifdef SK_BUILD_FOR_WIN
12// windows doesn't have roundf
13inline float roundf(float x) { return (x-floor(x))>0.5 ? ceil(x) : floor(x); }
14#endif
15
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#ifdef SK_DEBUG
17static void make_rgn(SkRegion* rgn, int left, int top, int right, int bottom,
18 size_t count, int32_t runs[]) {
19 SkIRect r;
20 r.set(left, top, right, bottom);
21
22 rgn->debugSetRuns(runs, count);
23 SkASSERT(rgn->getBounds() == r);
24}
25
26static void test_union_bug_1505668(SkRegion* ra, SkRegion* rb, SkRegion* rc) {
27 static int32_t dataA[] = {
28 0x00000001, 0x000001dd,
29 0x00000001, 0x0000000c, 0x0000000d, 0x00000025,
30 0x7fffffff, 0x000001de, 0x00000001, 0x00000025,
31 0x7fffffff, 0x000004b3, 0x00000001, 0x00000026,
32 0x7fffffff, 0x000004b4, 0x0000000c, 0x00000026,
33 0x7fffffff, 0x00000579, 0x00000000, 0x0000013a,
34 0x7fffffff, 0x000005d8, 0x00000000, 0x0000013b,
35 0x7fffffff, 0x7fffffff
36 };
37 make_rgn(ra, 0, 1, 315, 1496, SK_ARRAY_COUNT(dataA), dataA);
38
39 static int32_t dataB[] = {
40 0x000000b6, 0x000000c4,
41 0x000000a1, 0x000000f0, 0x7fffffff, 0x000000d6,
42 0x7fffffff, 0x000000e4, 0x00000070, 0x00000079,
43 0x000000a1, 0x000000b0, 0x7fffffff, 0x000000e6,
44 0x7fffffff, 0x000000f4, 0x00000070, 0x00000079,
45 0x000000a1, 0x000000b0, 0x7fffffff, 0x000000f6,
46 0x7fffffff, 0x00000104, 0x000000a1, 0x000000b0,
47 0x7fffffff, 0x7fffffff
48 };
49 make_rgn(rb, 112, 182, 240, 260, SK_ARRAY_COUNT(dataB), dataB);
50
51 rc->op(*ra, *rb, SkRegion::kUnion_Op);
52}
53#endif
54
reed@android.comf76bacf2009-05-13 14:00:33 +000055static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
56 dst->fLeft = (int)::roundf(src.fLeft * scale);
57 dst->fTop = (int)::roundf(src.fTop * scale);
58 dst->fRight = (int)::roundf(src.fRight * scale);
59 dst->fBottom = (int)::roundf(src.fBottom * scale);
60}
61
62static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
63 SkRegion tmp;
64 SkRegion::Iterator iter(src);
65
66 for (; !iter.done(); iter.next()) {
67 SkIRect r;
68 scale_rect(&r, iter.rect(), scale);
69 tmp.op(r, SkRegion::kUnion_Op);
70 }
71 dst->swap(tmp);
72}
73
74static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn,
75 const SkPaint& paint) {
76 SkRegion scaled;
77 scale_rgn(&scaled, rgn, 0.5f);
reed@android.com8a1c16f2008-12-17 15:59:43 +000078
reed@android.comf76bacf2009-05-13 14:00:33 +000079 SkRegion::Iterator iter(rgn);
80
reed@android.com8a1c16f2008-12-17 15:59:43 +000081 for (; !iter.done(); iter.next())
82 {
83 SkRect r;
84 r.set(iter.rect());
85 canvas->drawRect(r, paint);
86 }
87}
88
mike@reedtribe.org5fd92432011-05-05 01:59:48 +000089class RegionView : public SampleView {
reed@android.com8a1c16f2008-12-17 15:59:43 +000090public:
mike@reedtribe.org5fd92432011-05-05 01:59:48 +000091 RegionView() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000092 fBase.set(100, 100, 150, 150);
93 fRect = fBase;
94 fRect.inset(5, 5);
95 fRect.offset(25, 25);
mike@reedtribe.org5fd92432011-05-05 01:59:48 +000096 this->setBGColor(0xFFDDDDDD);
reed@android.com8a1c16f2008-12-17 15:59:43 +000097 }
98
mike@reedtribe.org5fd92432011-05-05 01:59:48 +000099 void build_rgn(SkRegion* rgn, SkRegion::Op op) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000100 rgn->setRect(fBase);
101 SkIRect r = fBase;
102 r.offset(75, 20);
103 rgn->op(r, SkRegion::kUnion_Op);
104 rgn->op(fRect, op);
105 }
106
107
108protected:
109 // overrides from SkEventSink
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000110 virtual bool onQuery(SkEvent* evt) {
111 if (SampleCode::TitleQ(*evt)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112 SampleCode::TitleR(evt, "Regions");
113 return true;
114 }
115 return this->INHERITED::onQuery(evt);
116 }
117
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000118 void drawOrig(SkCanvas* canvas, bool bg) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000119 SkRect r;
120 SkPaint paint;
121
122 paint.setStyle(SkPaint::kStroke_Style);
123 if (bg)
124 paint.setColor(0xFFBBBBBB);
125
126 r.set(fBase);
127 canvas->drawRect(r, paint);
128 r.set(fRect);
129 canvas->drawRect(r, paint);
130 }
131
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000132 void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133 SkRegion rgn;
134
135 this->build_rgn(&rgn, op);
136
137 {
138 SkRegion tmp, tmp2(rgn);
139
140 tmp = tmp2;
141 tmp.translate(5, -3);
142
143 {
144 char buffer[1000];
145 size_t size = tmp.flatten(NULL);
146 SkASSERT(size <= sizeof(buffer));
147 size_t size2 = tmp.flatten(buffer);
148 SkASSERT(size == size2);
149
150 SkRegion tmp3;
151 size2 = tmp3.unflatten(buffer);
152 SkASSERT(size == size2);
153
154 SkASSERT(tmp3 == tmp);
155 }
156
157 rgn.translate(20, 30, &tmp);
158 SkASSERT(rgn.isEmpty() || tmp != rgn);
159 tmp.translate(-20, -30);
160 SkASSERT(tmp == rgn);
161 }
162
163 this->drawOrig(canvas, true);
164
165 SkPaint paint;
166 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
167 paint_rgn(canvas, rgn, paint);
168
169 paint.setStyle(SkPaint::kStroke_Style);
170 paint.setColor(color);
171 paint_rgn(canvas, rgn, paint);
172 }
173
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000174 void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175 SkRegion rgn;
176 SkPath path;
177
178 this->build_rgn(&rgn, op);
179 rgn.getBoundaryPath(&path);
180
181 this->drawOrig(canvas, true);
182
183 SkPaint paint;
184
185 paint.setStyle(SkPaint::kFill_Style);
186 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
187 canvas->drawPath(path, paint);
188 paint.setColor(color);
189 paint.setStyle(SkPaint::kStroke_Style);
190 canvas->drawPath(path, paint);
191 }
192
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000193 virtual void onDrawContent(SkCanvas* canvas) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194#ifdef SK_DEBUG
195 if (true) {
196 SkRegion a, b, c;
197 test_union_bug_1505668(&a, &b, &c);
198
199 if (false) { // draw the result of the test
200 SkPaint paint;
201
202 canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
203 paint.setColor(SK_ColorRED);
204 paint_rgn(canvas, a, paint);
205 paint.setColor(0x800000FF);
206 paint_rgn(canvas, b, paint);
207 paint.setColor(SK_ColorBLACK);
208 paint.setStyle(SkPaint::kStroke_Style);
209 // paint_rgn(canvas, c, paint);
210 return;
211 }
212 }
213#endif
214
215 static const struct {
216 SkColor fColor;
217 const char* fName;
218 SkRegion::Op fOp;
219 } gOps[] = {
220 { SK_ColorBLACK, "Difference", SkRegion::kDifference_Op },
221 { SK_ColorRED, "Intersect", SkRegion::kIntersect_Op },
222 { 0xFF008800, "Union", SkRegion::kUnion_Op },
223 { SK_ColorBLUE, "XOR", SkRegion::kXOR_Op }
224 };
225
226 SkPaint textPaint;
227 textPaint.setAntiAlias(true);
228 textPaint.setTextSize(SK_Scalar1*24);
229
230 this->drawOrig(canvas, false);
231 canvas->save();
232 canvas->translate(SkIntToScalar(200), 0);
233 this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK);
234 canvas->restore();
235
236 canvas->translate(0, SkIntToScalar(200));
237
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000238 for (int op = 0; op < SK_ARRAY_COUNT(gOps); op++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 canvas->drawText(gOps[op].fName, strlen(gOps[op].fName), SkIntToScalar(75), SkIntToScalar(50), textPaint);
240
241 this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
242
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000243 canvas->save();
244 canvas->translate(0, SkIntToScalar(200));
245 this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
246 canvas->restore();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247
248 canvas->translate(SkIntToScalar(200), 0);
249 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000250 }
251
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000252 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
reed@android.com671cd652009-05-22 20:44:12 +0000253 return fRect.contains(SkScalarRound(x), SkScalarRound(y)) ? new Click(this) : NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254 }
255
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000256 virtual bool onClick(Click* click) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257 fRect.offset(click->fICurr.fX - click->fIPrev.fX,
258 click->fICurr.fY - click->fIPrev.fY);
reed@android.com671cd652009-05-22 20:44:12 +0000259 this->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000260 return true;
261 }
262
263private:
264 SkIRect fBase, fRect;
265
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000266 typedef SampleView INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267};
268
269//////////////////////////////////////////////////////////////////////////////
270
271static SkView* MyFactory() { return new RegionView; }
272static SkViewRegister reg(MyFactory);
273