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 #ifdef SK_BUILD_FOR_WIN
19 // windows doesn't have roundf
roundf(float x)20 inline float roundf(float x) { return (x-floor(x))>0.5 ? ceil(x) : floor(x); }
21 #endif
22
23 #ifdef SK_DEBUG
make_rgn(SkRegion * rgn,int left,int top,int right,int bottom,size_t count,int32_t runs[])24 static void make_rgn(SkRegion* rgn, int left, int top, int right, int bottom,
25 size_t count, int32_t runs[]) {
26 SkIRect r;
27 r.set(left, top, right, bottom);
28
29 rgn->debugSetRuns(runs, count);
30 SkASSERT(rgn->getBounds() == r);
31 }
32
test_union_bug_1505668(SkRegion * ra,SkRegion * rb,SkRegion * rc)33 static void test_union_bug_1505668(SkRegion* ra, SkRegion* rb, SkRegion* rc) {
34 static int32_t dataA[] = {
35 0x00000001, 0x000001dd,
36 0x00000001, 0x0000000c, 0x0000000d, 0x00000025,
37 0x7fffffff, 0x000001de, 0x00000001, 0x00000025,
38 0x7fffffff, 0x000004b3, 0x00000001, 0x00000026,
39 0x7fffffff, 0x000004b4, 0x0000000c, 0x00000026,
40 0x7fffffff, 0x00000579, 0x00000000, 0x0000013a,
41 0x7fffffff, 0x000005d8, 0x00000000, 0x0000013b,
42 0x7fffffff, 0x7fffffff
43 };
44 make_rgn(ra, 0, 1, 315, 1496, SK_ARRAY_COUNT(dataA), dataA);
45
46 static int32_t dataB[] = {
47 0x000000b6, 0x000000c4,
48 0x000000a1, 0x000000f0, 0x7fffffff, 0x000000d6,
49 0x7fffffff, 0x000000e4, 0x00000070, 0x00000079,
50 0x000000a1, 0x000000b0, 0x7fffffff, 0x000000e6,
51 0x7fffffff, 0x000000f4, 0x00000070, 0x00000079,
52 0x000000a1, 0x000000b0, 0x7fffffff, 0x000000f6,
53 0x7fffffff, 0x00000104, 0x000000a1, 0x000000b0,
54 0x7fffffff, 0x7fffffff
55 };
56 make_rgn(rb, 112, 182, 240, 260, SK_ARRAY_COUNT(dataB), dataB);
57
58 rc->op(*ra, *rb, SkRegion::kUnion_Op);
59 }
60 #endif
61
scale_rect(SkIRect * dst,const SkIRect & src,float scale)62 static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
63 dst->fLeft = (int)::roundf(src.fLeft * scale);
64 dst->fTop = (int)::roundf(src.fTop * scale);
65 dst->fRight = (int)::roundf(src.fRight * scale);
66 dst->fBottom = (int)::roundf(src.fBottom * scale);
67 }
68
scale_rgn(SkRegion * dst,const SkRegion & src,float scale)69 static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
70 SkRegion tmp;
71 SkRegion::Iterator iter(src);
72
73 for (; !iter.done(); iter.next()) {
74 SkIRect r;
75 scale_rect(&r, iter.rect(), scale);
76 tmp.op(r, SkRegion::kUnion_Op);
77 }
78 dst->swap(tmp);
79 }
80
paint_rgn(SkCanvas * canvas,const SkRegion & rgn,const SkPaint & paint)81 static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn,
82 const SkPaint& paint) {
83 SkRegion scaled;
84 scale_rgn(&scaled, rgn, 0.5f);
85
86 SkRegion::Iterator iter(rgn);
87
88 for (; !iter.done(); iter.next())
89 {
90 SkRect r;
91 r.set(iter.rect());
92 canvas->drawRect(r, paint);
93 }
94 }
95
96 class RegionView : public SampleView {
97 public:
RegionView()98 RegionView() {
99 fBase.set(100, 100, 150, 150);
100 fRect = fBase;
101 fRect.inset(5, 5);
102 fRect.offset(25, 25);
103 this->setBGColor(0xFFDDDDDD);
104 }
105
build_rgn(SkRegion * rgn,SkRegion::Op op)106 void build_rgn(SkRegion* rgn, SkRegion::Op op) {
107 rgn->setRect(fBase);
108 SkIRect r = fBase;
109 r.offset(75, 20);
110 rgn->op(r, SkRegion::kUnion_Op);
111 rgn->op(fRect, op);
112 }
113
114
115 protected:
116 // overrides from SkEventSink
onQuery(SkEvent * evt)117 virtual bool onQuery(SkEvent* evt) {
118 if (SampleCode::TitleQ(*evt)) {
119 SampleCode::TitleR(evt, "Regions");
120 return true;
121 }
122 return this->INHERITED::onQuery(evt);
123 }
124
drawOrig(SkCanvas * canvas,bool bg)125 void drawOrig(SkCanvas* canvas, bool bg) {
126 SkRect r;
127 SkPaint paint;
128
129 paint.setStyle(SkPaint::kStroke_Style);
130 if (bg)
131 paint.setColor(0xFFBBBBBB);
132
133 r.set(fBase);
134 canvas->drawRect(r, paint);
135 r.set(fRect);
136 canvas->drawRect(r, paint);
137 }
138
drawRgnOped(SkCanvas * canvas,SkRegion::Op op,SkColor color)139 void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
140 SkRegion rgn;
141
142 this->build_rgn(&rgn, op);
143
144 {
145 SkRegion tmp, tmp2(rgn);
146
147 tmp = tmp2;
148 tmp.translate(5, -3);
149
150 {
151 char buffer[1000];
152 size_t size = tmp.flatten(NULL);
153 SkASSERT(size <= sizeof(buffer));
154 size_t size2 = tmp.flatten(buffer);
155 SkASSERT(size == size2);
156
157 SkRegion tmp3;
158 size2 = tmp3.unflatten(buffer);
159 SkASSERT(size == size2);
160
161 SkASSERT(tmp3 == tmp);
162 }
163
164 rgn.translate(20, 30, &tmp);
165 SkASSERT(rgn.isEmpty() || tmp != rgn);
166 tmp.translate(-20, -30);
167 SkASSERT(tmp == rgn);
168 }
169
170 this->drawOrig(canvas, true);
171
172 SkPaint paint;
173 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
174 paint_rgn(canvas, rgn, paint);
175
176 paint.setStyle(SkPaint::kStroke_Style);
177 paint.setColor(color);
178 paint_rgn(canvas, rgn, paint);
179 }
180
drawPathOped(SkCanvas * canvas,SkRegion::Op op,SkColor color)181 void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
182 SkRegion rgn;
183 SkPath path;
184
185 this->build_rgn(&rgn, op);
186 rgn.getBoundaryPath(&path);
187
188 this->drawOrig(canvas, true);
189
190 SkPaint paint;
191
192 paint.setStyle(SkPaint::kFill_Style);
193 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
194 canvas->drawPath(path, paint);
195 paint.setColor(color);
196 paint.setStyle(SkPaint::kStroke_Style);
197 canvas->drawPath(path, paint);
198 }
199
onDrawContent(SkCanvas * canvas)200 virtual void onDrawContent(SkCanvas* canvas) {
201 #ifdef SK_DEBUG
202 if (true) {
203 SkRegion a, b, c;
204 test_union_bug_1505668(&a, &b, &c);
205
206 if (false) { // draw the result of the test
207 SkPaint paint;
208
209 canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
210 paint.setColor(SK_ColorRED);
211 paint_rgn(canvas, a, paint);
212 paint.setColor(0x800000FF);
213 paint_rgn(canvas, b, paint);
214 paint.setColor(SK_ColorBLACK);
215 paint.setStyle(SkPaint::kStroke_Style);
216 // paint_rgn(canvas, c, paint);
217 return;
218 }
219 }
220 #endif
221
222 static const struct {
223 SkColor fColor;
224 const char* fName;
225 SkRegion::Op fOp;
226 } gOps[] = {
227 { SK_ColorBLACK, "Difference", SkRegion::kDifference_Op },
228 { SK_ColorRED, "Intersect", SkRegion::kIntersect_Op },
229 { 0xFF008800, "Union", SkRegion::kUnion_Op },
230 { SK_ColorBLUE, "XOR", SkRegion::kXOR_Op }
231 };
232
233 SkPaint textPaint;
234 textPaint.setAntiAlias(true);
235 textPaint.setTextSize(SK_Scalar1*24);
236
237 this->drawOrig(canvas, false);
238 canvas->save();
239 canvas->translate(SkIntToScalar(200), 0);
240 this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK);
241 canvas->restore();
242
243 canvas->translate(0, SkIntToScalar(200));
244
245 for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); op++) {
246 canvas->drawText(gOps[op].fName, strlen(gOps[op].fName), SkIntToScalar(75), SkIntToScalar(50), textPaint);
247
248 this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
249
250 canvas->save();
251 canvas->translate(0, SkIntToScalar(200));
252 this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
253 canvas->restore();
254
255 canvas->translate(SkIntToScalar(200), 0);
256 }
257 }
258
onFindClickHandler(SkScalar x,SkScalar y)259 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
260 return fRect.contains(SkScalarRound(x), SkScalarRound(y)) ? new Click(this) : NULL;
261 }
262
onClick(Click * click)263 virtual bool onClick(Click* click) {
264 fRect.offset(click->fICurr.fX - click->fIPrev.fX,
265 click->fICurr.fY - click->fIPrev.fY);
266 this->inval(NULL);
267 return true;
268 }
269
270 private:
271 SkIRect fBase, fRect;
272
273 typedef SampleView INHERITED;
274 };
275
276 //////////////////////////////////////////////////////////////////////////////
277
MyFactory()278 static SkView* MyFactory() { return new RegionView; }
279 static SkViewRegister reg(MyFactory);
280
281