c25b0733dff4562cea14924cac090853f027191f
[platform/upstream/libSkiaSharp.git] / samplecode / SampleRegion.cpp
1
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  */
8 #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
18 static void test_strokerect(SkCanvas* canvas) {
19     int width = 100;
20     int height = 100;
21
22     SkBitmap bitmap;
23     bitmap.allocPixels(SkImageInfo::MakeA8(width*2, height*2));
24     bitmap.eraseColor(SK_ColorTRANSPARENT);
25
26     SkScalar dx = 20;
27     SkScalar dy = 20;
28
29     SkPath path;
30     path.addRect(0.0f, 0.0f,
31                  SkIntToScalar(width), SkIntToScalar(height),
32                  SkPath::kCW_Direction);
33     SkRect r = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
34
35     SkCanvas c(bitmap);
36     c.translate(dx, dy);
37
38     SkPaint paint;
39     paint.setStyle(SkPaint::kStroke_Style);
40     paint.setStrokeWidth(1);
41
42     // use the rect
43     c.clear(SK_ColorTRANSPARENT);
44     c.drawRect(r, paint);
45     canvas->drawBitmap(bitmap, 0, 0, NULL);
46
47     // use the path
48     c.clear(SK_ColorTRANSPARENT);
49     c.drawPath(path, paint);
50     canvas->drawBitmap(bitmap, SkIntToScalar(2*width), 0, NULL);
51 }
52
53 static void drawFadingText(SkCanvas* canvas,
54                            const char* text, size_t len, SkScalar x, SkScalar y,
55                            const SkPaint& paint) {
56     // Need a bounds for the text
57     SkRect bounds;
58     SkPaint::FontMetrics fm;
59
60     paint.getFontMetrics(&fm);
61     bounds.set(x, y + fm.fTop, x + paint.measureText(text, len), y + fm.fBottom);
62
63     // may need to outset bounds a little, to account for hinting and/or
64     // antialiasing
65     bounds.inset(-SkIntToScalar(2), -SkIntToScalar(2));
66
67     canvas->saveLayer(&bounds, NULL);
68     canvas->drawText(text, len, x, y, paint);
69
70     const SkPoint pts[] = {
71         { bounds.fLeft, y },
72         { bounds.fRight, y }
73     };
74     const SkColor colors[] = { SK_ColorBLACK, SK_ColorBLACK, 0 };
75
76     // pos[1] value is where we start to fade, relative to the width
77     // of our pts[] array.
78     const SkScalar pos[] = { 0, 0.9f, SK_Scalar1 };
79
80     SkShader* s = SkGradientShader::CreateLinear(pts, colors, pos, 3,
81                                                  SkShader::kClamp_TileMode);
82     SkPaint p;
83     p.setShader(s)->unref();
84     p.setXfermodeMode(SkXfermode::kDstIn_Mode);
85     canvas->drawRect(bounds, p);
86
87     canvas->restore();
88 }
89
90 static void test_text(SkCanvas* canvas) {
91     SkPaint paint;
92     paint.setAntiAlias(true);
93     paint.setTextSize(20);
94
95     const char* str = "Hamburgefons";
96     size_t len = strlen(str);
97     SkScalar x = 20;
98     SkScalar y = 20;
99
100     canvas->drawText(str, len, x, y, paint);
101
102     y += 20;
103
104     const SkPoint pts[] = { { x, y }, { x + paint.measureText(str, len), y } };
105     const SkColor colors[] = { SK_ColorBLACK, SK_ColorBLACK, 0 };
106     const SkScalar pos[] = { 0, 0.9f, 1 };
107     SkShader* s = SkGradientShader::CreateLinear(pts, colors, pos,
108                                                  SK_ARRAY_COUNT(colors),
109                                                  SkShader::kClamp_TileMode);
110     paint.setShader(s)->unref();
111     canvas->drawText(str, len, x, y, paint);
112
113     y += 20;
114     paint.setShader(NULL);
115     drawFadingText(canvas, str, len, x, y, paint);
116 }
117
118 #ifdef SK_BUILD_FOR_WIN
119 // windows doesn't have roundf
120 inline float roundf(float x) { return (x-floor(x))>0.5 ? ceil(x) : floor(x); }
121 #endif
122
123 #ifdef SK_DEBUG
124 static void make_rgn(SkRegion* rgn, int left, int top, int right, int bottom,
125                      int count, int32_t runs[]) {
126     SkIRect r;
127     r.set(left, top, right, bottom);
128
129     rgn->debugSetRuns(runs, count);
130     SkASSERT(rgn->getBounds() == r);
131 }
132
133 static void test_union_bug_1505668(SkRegion* ra, SkRegion* rb, SkRegion* rc) {
134     static int32_t dataA[] = {
135         0x00000001,
136         0x000001dd, 2, 0x00000001, 0x0000000c, 0x0000000d, 0x00000025, 0x7fffffff,
137         0x000001de, 1, 0x00000001, 0x00000025, 0x7fffffff,
138         0x000004b3, 1, 0x00000001, 0x00000026, 0x7fffffff,
139         0x000004b4, 1, 0x0000000c, 0x00000026, 0x7fffffff,
140         0x00000579, 1, 0x00000000, 0x0000013a, 0x7fffffff,
141         0x000005d8, 1, 0x00000000, 0x0000013b, 0x7fffffff,
142         0x7fffffff
143     };
144     make_rgn(ra, 0, 1, 315, 1496, SK_ARRAY_COUNT(dataA), dataA);
145
146     static int32_t dataB[] = {
147         0x000000b6,
148         0x000000c4, 1, 0x000000a1, 0x000000f0, 0x7fffffff,
149         0x000000d6, 0, 0x7fffffff,
150         0x000000e4, 2, 0x00000070, 0x00000079, 0x000000a1, 0x000000b0, 0x7fffffff,
151         0x000000e6, 0, 0x7fffffff,
152         0x000000f4, 2, 0x00000070, 0x00000079, 0x000000a1, 0x000000b0, 0x7fffffff,
153         0x000000f6, 0, 0x7fffffff,
154         0x00000104, 1, 0x000000a1, 0x000000b0, 0x7fffffff,
155         0x7fffffff
156     };
157     make_rgn(rb, 112, 182, 240, 260, SK_ARRAY_COUNT(dataB), dataB);
158
159     rc->op(*ra, *rb, SkRegion::kUnion_Op);
160 }
161 #endif
162
163 static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
164     dst->fLeft = (int)::roundf(src.fLeft * scale);
165     dst->fTop = (int)::roundf(src.fTop * scale);
166     dst->fRight = (int)::roundf(src.fRight * scale);
167     dst->fBottom = (int)::roundf(src.fBottom * scale);
168 }
169
170 static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
171     SkRegion tmp;
172     SkRegion::Iterator iter(src);
173
174     for (; !iter.done(); iter.next()) {
175         SkIRect r;
176         scale_rect(&r, iter.rect(), scale);
177         tmp.op(r, SkRegion::kUnion_Op);
178     }
179     dst->swap(tmp);
180 }
181
182 static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn,
183                       const SkPaint& paint) {
184     SkRegion scaled;
185     scale_rgn(&scaled, rgn, 0.5f);
186
187     SkRegion::Iterator  iter(rgn);
188
189     for (; !iter.done(); iter.next())
190     {
191         SkRect    r;
192         r.set(iter.rect());
193         canvas->drawRect(r, paint);
194     }
195 }
196
197 class RegionView : public SampleView {
198 public:
199     RegionView() {
200         fBase.set(100, 100, 150, 150);
201         fRect = fBase;
202         fRect.inset(5, 5);
203         fRect.offset(25, 25);
204         this->setBGColor(0xFFDDDDDD);
205     }
206
207     void build_base_rgn(SkRegion* rgn) {
208         rgn->setRect(fBase);
209         SkIRect r = fBase;
210         r.offset(75, 20);
211         rgn->op(r, SkRegion::kUnion_Op);
212     }
213
214     void build_rgn(SkRegion* rgn, SkRegion::Op op) {
215         build_base_rgn(rgn);
216         rgn->op(fRect, op);
217     }
218
219
220 protected:
221     // overrides from SkEventSink
222     bool onQuery(SkEvent* evt) SK_OVERRIDE {
223         if (SampleCode::TitleQ(*evt)) {
224             SampleCode::TitleR(evt, "Regions");
225             return true;
226         }
227         return this->INHERITED::onQuery(evt);
228     }
229
230     static void drawstr(SkCanvas* canvas, const char text[], const SkPoint& loc,
231                         bool hilite) {
232         SkPaint paint;
233         paint.setAntiAlias(true);
234         paint.setTextSize(SkIntToScalar(20));
235         paint.setColor(hilite ? SK_ColorRED : 0x40FF0000);
236         canvas->drawText(text, strlen(text), loc.fX, loc.fY, paint);
237     }
238
239     void drawPredicates(SkCanvas* canvas, const SkPoint pts[]) {
240         SkRegion rgn;
241         build_base_rgn(&rgn);
242
243         drawstr(canvas, "Intersects", pts[0], rgn.intersects(fRect));
244         drawstr(canvas, "Contains", pts[1], rgn.contains(fRect));
245     }
246
247     void drawOrig(SkCanvas* canvas, bool bg) {
248         SkRect      r;
249         SkPaint     paint;
250
251         paint.setStyle(SkPaint::kStroke_Style);
252         if (bg)
253             paint.setColor(0xFFBBBBBB);
254
255         SkRegion rgn;
256         build_base_rgn(&rgn);
257         paint_rgn(canvas, rgn, paint);
258
259         r.set(fRect);
260         canvas->drawRect(r, paint);
261     }
262
263     void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
264         SkRegion    rgn;
265
266         this->build_rgn(&rgn, op);
267
268         {
269             SkRegion tmp, tmp2(rgn);
270
271             tmp = tmp2;
272             tmp.translate(5, -3);
273
274             {
275                 char    buffer[1000];
276                 SkDEBUGCODE(size_t  size = ) tmp.writeToMemory(NULL);
277                 SkASSERT(size <= sizeof(buffer));
278                 SkDEBUGCODE(size_t  size2 = ) tmp.writeToMemory(buffer);
279                 SkASSERT(size == size2);
280
281                 SkRegion    tmp3;
282                 SkDEBUGCODE(size2 = ) tmp3.readFromMemory(buffer, 1000);
283                 SkASSERT(size == size2);
284
285                 SkASSERT(tmp3 == tmp);
286             }
287
288             rgn.translate(20, 30, &tmp);
289             SkASSERT(rgn.isEmpty() || tmp != rgn);
290             tmp.translate(-20, -30);
291             SkASSERT(tmp == rgn);
292         }
293
294         this->drawOrig(canvas, true);
295
296         SkPaint paint;
297         paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
298         paint_rgn(canvas, rgn, paint);
299
300         paint.setStyle(SkPaint::kStroke_Style);
301         paint.setColor(color);
302         paint_rgn(canvas, rgn, paint);
303     }
304
305     void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
306         SkRegion    rgn;
307         SkPath      path;
308
309         this->build_rgn(&rgn, op);
310         rgn.getBoundaryPath(&path);
311
312         this->drawOrig(canvas, true);
313
314         SkPaint paint;
315
316         paint.setStyle(SkPaint::kFill_Style);
317         paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
318         canvas->drawPath(path, paint);
319         paint.setColor(color);
320         paint.setStyle(SkPaint::kStroke_Style);
321         canvas->drawPath(path, paint);
322     }
323
324     void onDrawContent(SkCanvas* canvas) SK_OVERRIDE {
325         if (false) { // avoid bit rot, suppress warning
326             test_strokerect(canvas);
327             return;
328         }
329         if (false) { // avoid bit rot, suppress warning
330             test_text(canvas);
331             return;
332         }
333 #ifdef SK_DEBUG
334         if (true) {
335             SkRegion a, b, c;
336             test_union_bug_1505668(&a, &b, &c);
337
338             if (false) {    // draw the result of the test
339                 SkPaint paint;
340
341                 canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
342                 paint.setColor(SK_ColorRED);
343                 paint_rgn(canvas, a, paint);
344                 paint.setColor(0x800000FF);
345                 paint_rgn(canvas, b, paint);
346                 paint.setColor(SK_ColorBLACK);
347                 paint.setStyle(SkPaint::kStroke_Style);
348              //   paint_rgn(canvas, c, paint);
349                 return;
350             }
351         }
352 #endif
353         const SkPoint origins[] = {
354             { 30*SK_Scalar1, 50*SK_Scalar1 },
355             { 150*SK_Scalar1, 50*SK_Scalar1 },
356         };
357         this->drawPredicates(canvas, origins);
358
359         static const struct {
360             SkColor         fColor;
361             const char*     fName;
362             SkRegion::Op    fOp;
363         } gOps[] = {
364             { SK_ColorBLACK,    "Difference",   SkRegion::kDifference_Op    },
365             { SK_ColorRED,      "Intersect",    SkRegion::kIntersect_Op     },
366             { 0xFF008800,       "Union",        SkRegion::kUnion_Op         },
367             { SK_ColorBLUE,     "XOR",          SkRegion::kXOR_Op           }
368         };
369
370         SkPaint textPaint;
371         textPaint.setAntiAlias(true);
372         textPaint.setTextSize(SK_Scalar1*24);
373
374         this->drawOrig(canvas, false);
375         canvas->save();
376             canvas->translate(SkIntToScalar(200), 0);
377             this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK);
378         canvas->restore();
379
380         canvas->translate(0, SkIntToScalar(200));
381
382         for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); op++) {
383             canvas->drawText(gOps[op].fName, strlen(gOps[op].fName), SkIntToScalar(75), SkIntToScalar(50), textPaint);
384
385             this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
386
387             canvas->save();
388             canvas->translate(0, SkIntToScalar(200));
389             this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
390             canvas->restore();
391
392             canvas->translate(SkIntToScalar(200), 0);
393         }
394     }
395
396     virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y,
397                                               unsigned modi) SK_OVERRIDE {
398         return fRect.contains(SkScalarRoundToInt(x),
399                               SkScalarRoundToInt(y)) ? new Click(this) : NULL;
400     }
401
402     bool onClick(Click* click) SK_OVERRIDE {
403         fRect.offset(click->fICurr.fX - click->fIPrev.fX,
404                      click->fICurr.fY - click->fIPrev.fY);
405         this->inval(NULL);
406         return true;
407     }
408
409 private:
410     SkIRect    fBase, fRect;
411
412     typedef SampleView INHERITED;
413 };
414
415 //////////////////////////////////////////////////////////////////////////////
416
417 static SkView* MyFactory() { return new RegionView; }
418 static SkViewRegister reg(MyFactory);