blob: 62590006f912de541a287bbe70736c89d2afcf13 [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
11#ifdef SK_DEBUG
12static void make_rgn(SkRegion* rgn, int left, int top, int right, int bottom,
13 size_t count, int32_t runs[]) {
14 SkIRect r;
15 r.set(left, top, right, bottom);
16
17 rgn->debugSetRuns(runs, count);
18 SkASSERT(rgn->getBounds() == r);
19}
20
21static void test_union_bug_1505668(SkRegion* ra, SkRegion* rb, SkRegion* rc) {
22 static int32_t dataA[] = {
23 0x00000001, 0x000001dd,
24 0x00000001, 0x0000000c, 0x0000000d, 0x00000025,
25 0x7fffffff, 0x000001de, 0x00000001, 0x00000025,
26 0x7fffffff, 0x000004b3, 0x00000001, 0x00000026,
27 0x7fffffff, 0x000004b4, 0x0000000c, 0x00000026,
28 0x7fffffff, 0x00000579, 0x00000000, 0x0000013a,
29 0x7fffffff, 0x000005d8, 0x00000000, 0x0000013b,
30 0x7fffffff, 0x7fffffff
31 };
32 make_rgn(ra, 0, 1, 315, 1496, SK_ARRAY_COUNT(dataA), dataA);
33
34 static int32_t dataB[] = {
35 0x000000b6, 0x000000c4,
36 0x000000a1, 0x000000f0, 0x7fffffff, 0x000000d6,
37 0x7fffffff, 0x000000e4, 0x00000070, 0x00000079,
38 0x000000a1, 0x000000b0, 0x7fffffff, 0x000000e6,
39 0x7fffffff, 0x000000f4, 0x00000070, 0x00000079,
40 0x000000a1, 0x000000b0, 0x7fffffff, 0x000000f6,
41 0x7fffffff, 0x00000104, 0x000000a1, 0x000000b0,
42 0x7fffffff, 0x7fffffff
43 };
44 make_rgn(rb, 112, 182, 240, 260, SK_ARRAY_COUNT(dataB), dataB);
45
46 rc->op(*ra, *rb, SkRegion::kUnion_Op);
47}
48#endif
49
reed@android.comf76bacf2009-05-13 14:00:33 +000050static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
51 dst->fLeft = (int)::roundf(src.fLeft * scale);
52 dst->fTop = (int)::roundf(src.fTop * scale);
53 dst->fRight = (int)::roundf(src.fRight * scale);
54 dst->fBottom = (int)::roundf(src.fBottom * scale);
55}
56
57static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
58 SkRegion tmp;
59 SkRegion::Iterator iter(src);
60
61 for (; !iter.done(); iter.next()) {
62 SkIRect r;
63 scale_rect(&r, iter.rect(), scale);
64 tmp.op(r, SkRegion::kUnion_Op);
65 }
66 dst->swap(tmp);
67}
68
69static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn,
70 const SkPaint& paint) {
71 SkRegion scaled;
72 scale_rgn(&scaled, rgn, 0.5f);
reed@android.com8a1c16f2008-12-17 15:59:43 +000073
reed@android.comf76bacf2009-05-13 14:00:33 +000074 SkRegion::Iterator iter(rgn);
75
reed@android.com8a1c16f2008-12-17 15:59:43 +000076 for (; !iter.done(); iter.next())
77 {
78 SkRect r;
79 r.set(iter.rect());
80 canvas->drawRect(r, paint);
81 }
82}
83
84class RegionView : public SkView {
85public:
86 RegionView()
87 {
88 fBase.set(100, 100, 150, 150);
89 fRect = fBase;
90 fRect.inset(5, 5);
91 fRect.offset(25, 25);
92 }
93
94 void build_rgn(SkRegion* rgn, SkRegion::Op op)
95 {
96 rgn->setRect(fBase);
97 SkIRect r = fBase;
98 r.offset(75, 20);
99 rgn->op(r, SkRegion::kUnion_Op);
100 rgn->op(fRect, op);
101 }
102
103
104protected:
105 // overrides from SkEventSink
106 virtual bool onQuery(SkEvent* evt)
107 {
108 if (SampleCode::TitleQ(*evt))
109 {
110 SampleCode::TitleR(evt, "Regions");
111 return true;
112 }
113 return this->INHERITED::onQuery(evt);
114 }
115
116 void drawOrig(SkCanvas* canvas, bool bg)
117 {
118 SkRect r;
119 SkPaint paint;
120
121 paint.setStyle(SkPaint::kStroke_Style);
122 if (bg)
123 paint.setColor(0xFFBBBBBB);
124
125 r.set(fBase);
126 canvas->drawRect(r, paint);
127 r.set(fRect);
128 canvas->drawRect(r, paint);
129 }
130
131 void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color)
132 {
133 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
174 void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color)
175 {
176 SkRegion rgn;
177 SkPath path;
178
179 this->build_rgn(&rgn, op);
180 rgn.getBoundaryPath(&path);
181
182 this->drawOrig(canvas, true);
183
184 SkPaint paint;
185
186 paint.setStyle(SkPaint::kFill_Style);
187 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
188 canvas->drawPath(path, paint);
189 paint.setColor(color);
190 paint.setStyle(SkPaint::kStroke_Style);
191 canvas->drawPath(path, paint);
192 }
193
194 void drawBG(SkCanvas* canvas)
195 {
196 canvas->drawColor(0xFFDDDDDD);
197 return;
198
199#if 0
200 SkColorTable ct;
201 SkPMColor colors[] = { SK_ColorRED, SK_ColorBLUE };
202 ct.setColors(colors, 2);
203 ct.setFlags(ct.getFlags() | SkColorTable::kColorsAreOpaque_Flag);
204
205 SkBitmap bm;
206 bm.setConfig(SkBitmap::kIndex8_Config, 20, 20, 21);
207 bm.setColorTable(&ct);
208 bm.allocPixels();
209 sk_memset16((uint16_t*)bm.getAddr8(0, 0), 0x0001, bm.rowBytes() * bm.height() / 2);
210#endif
211#if 0
212 SkBitmap bm;
213 bm.setConfig(SkBitmap::kRGB_565_Config, 20, 20, 42);
214 bm.allocPixels();
215 sk_memset32((uint32_t*)bm.getAddr16(0, 0), 0x0000FFFF, bm.rowBytes() * bm.height() / 4);
216#endif
217#if 1
218 SkBitmap bm;
219 bm.setConfig(SkBitmap::kARGB_8888_Config, 20, 20);
220 bm.allocPixels();
221 sk_memset32((uint32_t*)bm.getAddr32(0, 0), 0xFFDDDDDD, bm.rowBytes() * bm.height() / 4);
222#endif
223
224 SkPaint paint;
225
226// SkShader* shader = SkShader::CreateBitmapShader(bm, false, SkPaint::kBilinear_FilterType, SkShader::kRepeat_TileMode);
227 SkPoint pts[] = { 0, 0, SkIntToScalar(100), SkIntToScalar(0) };
228 SkColor colors[] = { SK_ColorBLACK, SK_ColorWHITE };
reed@android.com671cd652009-05-22 20:44:12 +0000229 SkShader* shader = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kMirror_TileMode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000230 paint.setShader(shader)->unref();
231
232 canvas->drawPaint(paint);
233 }
234
235 virtual void onDraw(SkCanvas* canvas)
236 {
237 if (true) {
238 SkRect r = { 0, 0, 1 << 30, 1 << 30 };
239 bool open = canvas->clipRect(r);
240 SkDebugf("---- giant clip is %d\n", open);
241 }
242 this->drawBG(canvas);
243
reed@android.com3469c762009-02-24 19:03:20 +0000244 if (false) {
245 SkPaint paint;
246 paint.setAntiAlias(true);
247 SkBitmap bm;
248 bm.setConfig(SkBitmap::kA8_Config, 100, 100);
249 bm.allocPixels();
250 bm.eraseColor(0);
251 SkCanvas c(bm);
252 c.drawCircle(50, 50, 50, paint);
253
254 paint.setColor(SK_ColorBLUE);
255 canvas->drawBitmap(bm, 0, 0, &paint);
256 canvas->scale(SK_Scalar1/2, SK_Scalar1/2);
257 paint.setColor(SK_ColorRED);
258 canvas->drawBitmap(bm, 0, 0, &paint);
259 return;
260 }
261
reed@android.com8a1c16f2008-12-17 15:59:43 +0000262#ifdef SK_DEBUG
263 if (true) {
264 SkRegion a, b, c;
265 test_union_bug_1505668(&a, &b, &c);
266
267 if (false) { // draw the result of the test
268 SkPaint paint;
269
270 canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
271 paint.setColor(SK_ColorRED);
272 paint_rgn(canvas, a, paint);
273 paint.setColor(0x800000FF);
274 paint_rgn(canvas, b, paint);
275 paint.setColor(SK_ColorBLACK);
276 paint.setStyle(SkPaint::kStroke_Style);
277 // paint_rgn(canvas, c, paint);
278 return;
279 }
280 }
281#endif
282
283 static const struct {
284 SkColor fColor;
285 const char* fName;
286 SkRegion::Op fOp;
287 } gOps[] = {
288 { SK_ColorBLACK, "Difference", SkRegion::kDifference_Op },
289 { SK_ColorRED, "Intersect", SkRegion::kIntersect_Op },
290 { 0xFF008800, "Union", SkRegion::kUnion_Op },
291 { SK_ColorBLUE, "XOR", SkRegion::kXOR_Op }
292 };
293
294 SkPaint textPaint;
295 textPaint.setAntiAlias(true);
296 textPaint.setTextSize(SK_Scalar1*24);
297
298 this->drawOrig(canvas, false);
299 canvas->save();
300 canvas->translate(SkIntToScalar(200), 0);
301 this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK);
302 canvas->restore();
303
304 canvas->translate(0, SkIntToScalar(200));
305
306 for (int op = 0; op < SK_ARRAY_COUNT(gOps); op++)
307 {
308 canvas->drawText(gOps[op].fName, strlen(gOps[op].fName), SkIntToScalar(75), SkIntToScalar(50), textPaint);
309
310 this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
311
312 if (true)
313 {
314 canvas->save();
315 canvas->translate(0, SkIntToScalar(200));
316 this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
317 canvas->restore();
318 }
319
320 canvas->translate(SkIntToScalar(200), 0);
321 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000322 }
323
324 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y)
325 {
reed@android.com671cd652009-05-22 20:44:12 +0000326 return fRect.contains(SkScalarRound(x), SkScalarRound(y)) ? new Click(this) : NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000327 }
328
329 virtual bool onClick(Click* click)
330 {
331 fRect.offset(click->fICurr.fX - click->fIPrev.fX,
332 click->fICurr.fY - click->fIPrev.fY);
reed@android.com671cd652009-05-22 20:44:12 +0000333 this->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334 return true;
335 }
336
337private:
338 SkIRect fBase, fRect;
339
340 typedef SkView INHERITED;
341};
342
343//////////////////////////////////////////////////////////////////////////////
344
345static SkView* MyFactory() { return new RegionView; }
346static SkViewRegister reg(MyFactory);
347