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