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