• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
test_strokerect(SkCanvas * canvas)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 
drawFadingText(SkCanvas * canvas,const char * text,size_t len,SkScalar x,SkScalar y,const SkPaint & paint)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 
test_text(SkCanvas * canvas)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
roundf(float x)120 inline float roundf(float x) { return (x-floor(x))>0.5 ? ceil(x) : floor(x); }
121 #endif
122 
123 #ifdef SK_DEBUG
make_rgn(SkRegion * rgn,int left,int top,int right,int bottom,int count,int32_t runs[])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 
test_union_bug_1505668(SkRegion * ra,SkRegion * rb,SkRegion * rc)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 
scale_rect(SkIRect * dst,const SkIRect & src,float scale)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 
scale_rgn(SkRegion * dst,const SkRegion & src,float scale)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 
paint_rgn(SkCanvas * canvas,const SkRegion & rgn,const SkPaint & paint)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:
RegionView()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 
build_base_rgn(SkRegion * rgn)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 
build_rgn(SkRegion * rgn,SkRegion::Op op)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
onQuery(SkEvent * evt)222     virtual bool onQuery(SkEvent* evt) {
223         if (SampleCode::TitleQ(*evt)) {
224             SampleCode::TitleR(evt, "Regions");
225             return true;
226         }
227         return this->INHERITED::onQuery(evt);
228     }
229 
drawstr(SkCanvas * canvas,const char text[],const SkPoint & loc,bool hilite)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 
drawPredicates(SkCanvas * canvas,const SkPoint pts[])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 
drawOrig(SkCanvas * canvas,bool bg)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 
drawRgnOped(SkCanvas * canvas,SkRegion::Op op,SkColor color)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 
drawPathOped(SkCanvas * canvas,SkRegion::Op op,SkColor color)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 
onDrawContent(SkCanvas * canvas)324     virtual void onDrawContent(SkCanvas* canvas) {
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 
onFindClickHandler(SkScalar x,SkScalar y,unsigned modi)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 
onClick(Click * click)402     virtual bool onClick(Click* click) {
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 
MyFactory()417 static SkView* MyFactory() { return new RegionView; }
418 static SkViewRegister reg(MyFactory);
419