blob: 8777050b14185c4e775989a6b4cbdb3b17124559 [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
89class RegionView : public SkView {
90public:
91 RegionView()
92 {
93 fBase.set(100, 100, 150, 150);
94 fRect = fBase;
95 fRect.inset(5, 5);
96 fRect.offset(25, 25);
97 }
98
99 void build_rgn(SkRegion* rgn, SkRegion::Op op)
100 {
101 rgn->setRect(fBase);
102 SkIRect r = fBase;
103 r.offset(75, 20);
104 rgn->op(r, SkRegion::kUnion_Op);
105 rgn->op(fRect, op);
106 }
107
108
109protected:
110 // overrides from SkEventSink
111 virtual bool onQuery(SkEvent* evt)
112 {
113 if (SampleCode::TitleQ(*evt))
114 {
115 SampleCode::TitleR(evt, "Regions");
116 return true;
117 }
118 return this->INHERITED::onQuery(evt);
119 }
120
121 void drawOrig(SkCanvas* canvas, bool bg)
122 {
123 SkRect r;
124 SkPaint paint;
125
126 paint.setStyle(SkPaint::kStroke_Style);
127 if (bg)
128 paint.setColor(0xFFBBBBBB);
129
130 r.set(fBase);
131 canvas->drawRect(r, paint);
132 r.set(fRect);
133 canvas->drawRect(r, paint);
134 }
135
136 void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color)
137 {
138 SkRegion rgn;
139
140 this->build_rgn(&rgn, op);
141
142 {
143 SkRegion tmp, tmp2(rgn);
144
145 tmp = tmp2;
146 tmp.translate(5, -3);
147
148 {
149 char buffer[1000];
150 size_t size = tmp.flatten(NULL);
151 SkASSERT(size <= sizeof(buffer));
152 size_t size2 = tmp.flatten(buffer);
153 SkASSERT(size == size2);
154
155 SkRegion tmp3;
156 size2 = tmp3.unflatten(buffer);
157 SkASSERT(size == size2);
158
159 SkASSERT(tmp3 == tmp);
160 }
161
162 rgn.translate(20, 30, &tmp);
163 SkASSERT(rgn.isEmpty() || tmp != rgn);
164 tmp.translate(-20, -30);
165 SkASSERT(tmp == rgn);
166 }
167
168 this->drawOrig(canvas, true);
169
170 SkPaint paint;
171 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
172 paint_rgn(canvas, rgn, paint);
173
174 paint.setStyle(SkPaint::kStroke_Style);
175 paint.setColor(color);
176 paint_rgn(canvas, rgn, paint);
177 }
178
179 void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color)
180 {
181 SkRegion rgn;
182 SkPath path;
183
184 this->build_rgn(&rgn, op);
185 rgn.getBoundaryPath(&path);
186
187 this->drawOrig(canvas, true);
188
189 SkPaint paint;
190
191 paint.setStyle(SkPaint::kFill_Style);
192 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
193 canvas->drawPath(path, paint);
194 paint.setColor(color);
195 paint.setStyle(SkPaint::kStroke_Style);
196 canvas->drawPath(path, paint);
197 }
198
199 void drawBG(SkCanvas* canvas)
200 {
201 canvas->drawColor(0xFFDDDDDD);
202 return;
203
204#if 0
205 SkColorTable ct;
206 SkPMColor colors[] = { SK_ColorRED, SK_ColorBLUE };
207 ct.setColors(colors, 2);
208 ct.setFlags(ct.getFlags() | SkColorTable::kColorsAreOpaque_Flag);
209
210 SkBitmap bm;
211 bm.setConfig(SkBitmap::kIndex8_Config, 20, 20, 21);
212 bm.setColorTable(&ct);
213 bm.allocPixels();
214 sk_memset16((uint16_t*)bm.getAddr8(0, 0), 0x0001, bm.rowBytes() * bm.height() / 2);
215#endif
216#if 0
217 SkBitmap bm;
218 bm.setConfig(SkBitmap::kRGB_565_Config, 20, 20, 42);
219 bm.allocPixels();
220 sk_memset32((uint32_t*)bm.getAddr16(0, 0), 0x0000FFFF, bm.rowBytes() * bm.height() / 4);
221#endif
222#if 1
223 SkBitmap bm;
224 bm.setConfig(SkBitmap::kARGB_8888_Config, 20, 20);
225 bm.allocPixels();
226 sk_memset32((uint32_t*)bm.getAddr32(0, 0), 0xFFDDDDDD, bm.rowBytes() * bm.height() / 4);
227#endif
228
229 SkPaint paint;
230
231// SkShader* shader = SkShader::CreateBitmapShader(bm, false, SkPaint::kBilinear_FilterType, SkShader::kRepeat_TileMode);
232 SkPoint pts[] = { 0, 0, SkIntToScalar(100), SkIntToScalar(0) };
233 SkColor colors[] = { SK_ColorBLACK, SK_ColorWHITE };
reed@android.com671cd652009-05-22 20:44:12 +0000234 SkShader* shader = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kMirror_TileMode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000235 paint.setShader(shader)->unref();
236
237 canvas->drawPaint(paint);
238 }
239
reed@android.comf2b98d62010-12-20 18:26:13 +0000240 virtual void onDraw(SkCanvas* canvas) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241 this->drawBG(canvas);
242
reed@android.com3469c762009-02-24 19:03:20 +0000243 if (false) {
244 SkPaint paint;
245 paint.setAntiAlias(true);
246 SkBitmap bm;
247 bm.setConfig(SkBitmap::kA8_Config, 100, 100);
248 bm.allocPixels();
249 bm.eraseColor(0);
250 SkCanvas c(bm);
251 c.drawCircle(50, 50, 50, paint);
252
253 paint.setColor(SK_ColorBLUE);
254 canvas->drawBitmap(bm, 0, 0, &paint);
255 canvas->scale(SK_Scalar1/2, SK_Scalar1/2);
256 paint.setColor(SK_ColorRED);
257 canvas->drawBitmap(bm, 0, 0, &paint);
258 return;
259 }
260
reed@android.com8a1c16f2008-12-17 15:59:43 +0000261#ifdef SK_DEBUG
262 if (true) {
263 SkRegion a, b, c;
264 test_union_bug_1505668(&a, &b, &c);
265
266 if (false) { // draw the result of the test
267 SkPaint paint;
268
269 canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
270 paint.setColor(SK_ColorRED);
271 paint_rgn(canvas, a, paint);
272 paint.setColor(0x800000FF);
273 paint_rgn(canvas, b, paint);
274 paint.setColor(SK_ColorBLACK);
275 paint.setStyle(SkPaint::kStroke_Style);
276 // paint_rgn(canvas, c, paint);
277 return;
278 }
279 }
280#endif
281
282 static const struct {
283 SkColor fColor;
284 const char* fName;
285 SkRegion::Op fOp;
286 } gOps[] = {
287 { SK_ColorBLACK, "Difference", SkRegion::kDifference_Op },
288 { SK_ColorRED, "Intersect", SkRegion::kIntersect_Op },
289 { 0xFF008800, "Union", SkRegion::kUnion_Op },
290 { SK_ColorBLUE, "XOR", SkRegion::kXOR_Op }
291 };
292
293 SkPaint textPaint;
294 textPaint.setAntiAlias(true);
295 textPaint.setTextSize(SK_Scalar1*24);
296
297 this->drawOrig(canvas, false);
298 canvas->save();
299 canvas->translate(SkIntToScalar(200), 0);
300 this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK);
301 canvas->restore();
302
303 canvas->translate(0, SkIntToScalar(200));
304
305 for (int op = 0; op < SK_ARRAY_COUNT(gOps); op++)
306 {
307 canvas->drawText(gOps[op].fName, strlen(gOps[op].fName), SkIntToScalar(75), SkIntToScalar(50), textPaint);
308
309 this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
310
311 if (true)
312 {
313 canvas->save();
314 canvas->translate(0, SkIntToScalar(200));
315 this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
316 canvas->restore();
317 }
318
319 canvas->translate(SkIntToScalar(200), 0);
320 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000321 }
322
323 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y)
324 {
reed@android.com671cd652009-05-22 20:44:12 +0000325 return fRect.contains(SkScalarRound(x), SkScalarRound(y)) ? new Click(this) : NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000326 }
327
328 virtual bool onClick(Click* click)
329 {
330 fRect.offset(click->fICurr.fX - click->fIPrev.fX,
331 click->fICurr.fY - click->fIPrev.fY);
reed@android.com671cd652009-05-22 20:44:12 +0000332 this->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000333 return true;
334 }
335
336private:
337 SkIRect fBase, fRect;
338
339 typedef SkView INHERITED;
340};
341
342//////////////////////////////////////////////////////////////////////////////
343
344static SkView* MyFactory() { return new RegionView; }
345static SkViewRegister reg(MyFactory);
346