blob: 0525f466f7273876d9d5d9aeab4dddbbb6845f2c [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
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 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#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
reed@google.com4b5894c2012-05-02 18:03:32 +000018static void test_strokerect(SkCanvas* canvas) {
19 int width = 100;
20 int height = 100;
21
22 SkBitmap bitmap;
23 bitmap.setConfig(SkBitmap::kA8_Config, width*2, height*2);
24 bitmap.allocPixels();
25 bitmap.eraseColor(0);
26
27 SkScalar dx = 20;
28 SkScalar dy = 20;
29
30 SkPath path;
robertphillips@google.com4debcac2012-05-14 16:33:36 +000031 path.addRect(0.0f, 0.0f,
32 SkIntToScalar(width), SkIntToScalar(height),
33 SkPath::kCW_Direction);
34 SkRect r = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
reed@google.com4b5894c2012-05-02 18:03:32 +000035
36 SkCanvas c(bitmap);
37 c.translate(dx, dy);
38
39 SkPaint paint;
40 paint.setStyle(SkPaint::kStroke_Style);
41 paint.setStrokeWidth(1);
42
43 // use the rect
44 c.clear(0);
45 c.drawRect(r, paint);
46 canvas->drawBitmap(bitmap, 0, 0, NULL);
47
48 // use the path
49 c.clear(0);
50 c.drawPath(path, paint);
robertphillips@google.com4debcac2012-05-14 16:33:36 +000051 canvas->drawBitmap(bitmap, SkIntToScalar(2*width), 0, NULL);
reed@google.com4b5894c2012-05-02 18:03:32 +000052}
53
54static void drawFadingText(SkCanvas* canvas,
55 const char* text, size_t len, SkScalar x, SkScalar y,
56 const SkPaint& paint) {
57 // Need a bounds for the text
58 SkRect bounds;
59 SkPaint::FontMetrics fm;
60
61 paint.getFontMetrics(&fm);
62 bounds.set(x, y + fm.fTop, x + paint.measureText(text, len), y + fm.fBottom);
63
64 // may need to outset bounds a little, to account for hinting and/or
65 // antialiasing
66 bounds.inset(-SkIntToScalar(2), -SkIntToScalar(2));
67
68 canvas->saveLayer(&bounds, NULL);
69 canvas->drawText(text, len, x, y, paint);
70
71 const SkPoint pts[] = {
72 { bounds.fLeft, y },
73 { bounds.fRight, y }
74 };
75 const SkColor colors[] = { SK_ColorBLACK, SK_ColorBLACK, 0 };
76
77 // pos[1] value is where we start to fade, relative to the width
78 // of our pts[] array.
robertphillips@google.com4debcac2012-05-14 16:33:36 +000079 const SkScalar pos[] = { 0, SkFloatToScalar(0.9f), SK_Scalar1 };
reed@google.com4b5894c2012-05-02 18:03:32 +000080
81 SkShader* s = SkGradientShader::CreateLinear(pts, colors, pos, 3,
82 SkShader::kClamp_TileMode);
83 SkPaint p;
84 p.setShader(s)->unref();
85 p.setXfermodeMode(SkXfermode::kDstIn_Mode);
86 canvas->drawRect(bounds, p);
87
88 canvas->restore();
89}
90
91static void test_text(SkCanvas* canvas) {
92 SkPaint paint;
93 paint.setAntiAlias(true);
94 paint.setTextSize(20);
95
96 const char* str = "Hamburgefons";
97 size_t len = strlen(str);
98 SkScalar x = 20;
99 SkScalar y = 20;
100
101 canvas->drawText(str, len, x, y, paint);
102
103 y += 20;
104
105 const SkPoint pts[] = { { x, y }, { x + paint.measureText(str, len), y } };
106 const SkColor colors[] = { SK_ColorBLACK, SK_ColorBLACK, 0 };
107 const SkScalar pos[] = { 0, 0.9f, 1 };
108 SkShader* s = SkGradientShader::CreateLinear(pts, colors, pos,
109 SK_ARRAY_COUNT(colors),
110 SkShader::kClamp_TileMode);
111 paint.setShader(s)->unref();
112 canvas->drawText(str, len, x, y, paint);
113
114 y += 20;
115 paint.setShader(NULL);
116 drawFadingText(canvas, str, len, x, y, paint);
117}
118
reed@android.comf2b98d62010-12-20 18:26:13 +0000119#ifdef SK_BUILD_FOR_WIN
120// windows doesn't have roundf
121inline float roundf(float x) { return (x-floor(x))>0.5 ? ceil(x) : floor(x); }
122#endif
123
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124#ifdef SK_DEBUG
125static void make_rgn(SkRegion* rgn, int left, int top, int right, int bottom,
126 size_t count, int32_t runs[]) {
127 SkIRect r;
128 r.set(left, top, right, bottom);
129
130 rgn->debugSetRuns(runs, count);
131 SkASSERT(rgn->getBounds() == r);
132}
133
134static void test_union_bug_1505668(SkRegion* ra, SkRegion* rb, SkRegion* rc) {
135 static int32_t dataA[] = {
reed@google.com4b5894c2012-05-02 18:03:32 +0000136 0x00000001,
137 0x000001dd, 2, 0x00000001, 0x0000000c, 0x0000000d, 0x00000025, 0x7fffffff,
138 0x000001de, 1, 0x00000001, 0x00000025, 0x7fffffff,
139 0x000004b3, 1, 0x00000001, 0x00000026, 0x7fffffff,
140 0x000004b4, 1, 0x0000000c, 0x00000026, 0x7fffffff,
141 0x00000579, 1, 0x00000000, 0x0000013a, 0x7fffffff,
142 0x000005d8, 1, 0x00000000, 0x0000013b, 0x7fffffff,
143 0x7fffffff
reed@android.com8a1c16f2008-12-17 15:59:43 +0000144 };
145 make_rgn(ra, 0, 1, 315, 1496, SK_ARRAY_COUNT(dataA), dataA);
146
147 static int32_t dataB[] = {
reed@google.com4b5894c2012-05-02 18:03:32 +0000148 0x000000b6,
149 0x000000c4, 1, 0x000000a1, 0x000000f0, 0x7fffffff,
150 0x000000d6, 0, 0x7fffffff,
151 0x000000e4, 2, 0x00000070, 0x00000079, 0x000000a1, 0x000000b0, 0x7fffffff,
152 0x000000e6, 0, 0x7fffffff,
153 0x000000f4, 2, 0x00000070, 0x00000079, 0x000000a1, 0x000000b0, 0x7fffffff,
154 0x000000f6, 0, 0x7fffffff,
155 0x00000104, 1, 0x000000a1, 0x000000b0, 0x7fffffff,
156 0x7fffffff
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157 };
158 make_rgn(rb, 112, 182, 240, 260, SK_ARRAY_COUNT(dataB), dataB);
159
160 rc->op(*ra, *rb, SkRegion::kUnion_Op);
161}
162#endif
163
reed@android.comf76bacf2009-05-13 14:00:33 +0000164static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
165 dst->fLeft = (int)::roundf(src.fLeft * scale);
166 dst->fTop = (int)::roundf(src.fTop * scale);
167 dst->fRight = (int)::roundf(src.fRight * scale);
168 dst->fBottom = (int)::roundf(src.fBottom * scale);
169}
170
171static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
172 SkRegion tmp;
173 SkRegion::Iterator iter(src);
174
175 for (; !iter.done(); iter.next()) {
176 SkIRect r;
177 scale_rect(&r, iter.rect(), scale);
178 tmp.op(r, SkRegion::kUnion_Op);
179 }
180 dst->swap(tmp);
181}
182
183static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn,
184 const SkPaint& paint) {
185 SkRegion scaled;
186 scale_rgn(&scaled, rgn, 0.5f);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187
reed@android.comf76bacf2009-05-13 14:00:33 +0000188 SkRegion::Iterator iter(rgn);
189
reed@android.com8a1c16f2008-12-17 15:59:43 +0000190 for (; !iter.done(); iter.next())
191 {
192 SkRect r;
193 r.set(iter.rect());
194 canvas->drawRect(r, paint);
195 }
196}
197
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000198class RegionView : public SampleView {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199public:
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000200 RegionView() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201 fBase.set(100, 100, 150, 150);
202 fRect = fBase;
203 fRect.inset(5, 5);
204 fRect.offset(25, 25);
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000205 this->setBGColor(0xFFDDDDDD);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000206 }
207
reed@google.com4b5894c2012-05-02 18:03:32 +0000208 void build_base_rgn(SkRegion* rgn) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209 rgn->setRect(fBase);
210 SkIRect r = fBase;
211 r.offset(75, 20);
212 rgn->op(r, SkRegion::kUnion_Op);
reed@google.com4b5894c2012-05-02 18:03:32 +0000213 }
214
215 void build_rgn(SkRegion* rgn, SkRegion::Op op) {
216 build_base_rgn(rgn);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000217 rgn->op(fRect, op);
218 }
219
220
221protected:
222 // overrides from SkEventSink
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000223 virtual bool onQuery(SkEvent* evt) {
224 if (SampleCode::TitleQ(*evt)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 SampleCode::TitleR(evt, "Regions");
226 return true;
227 }
228 return this->INHERITED::onQuery(evt);
229 }
230
reed@google.com4b5894c2012-05-02 18:03:32 +0000231 static void drawstr(SkCanvas* canvas, const char text[], const SkPoint& loc,
232 bool hilite) {
233 SkPaint paint;
234 paint.setAntiAlias(true);
235 paint.setTextSize(SkIntToScalar(20));
236 paint.setColor(hilite ? SK_ColorRED : 0x40FF0000);
237 canvas->drawText(text, strlen(text), loc.fX, loc.fY, paint);
238 }
239
240 void drawPredicates(SkCanvas* canvas, const SkPoint pts[]) {
241 SkRegion rgn;
242 build_base_rgn(&rgn);
243
244 drawstr(canvas, "Intersects", pts[0], rgn.intersects(fRect));
245 drawstr(canvas, "Contains", pts[1], rgn.contains(fRect));
246 }
247
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000248 void drawOrig(SkCanvas* canvas, bool bg) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000249 SkRect r;
250 SkPaint paint;
251
252 paint.setStyle(SkPaint::kStroke_Style);
253 if (bg)
254 paint.setColor(0xFFBBBBBB);
255
reed@google.com4b5894c2012-05-02 18:03:32 +0000256 SkRegion rgn;
257 build_base_rgn(&rgn);
258 paint_rgn(canvas, rgn, paint);
259
reed@android.com8a1c16f2008-12-17 15:59:43 +0000260 r.set(fRect);
261 canvas->drawRect(r, paint);
262 }
263
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000264 void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000265 SkRegion rgn;
266
267 this->build_rgn(&rgn, op);
268
269 {
270 SkRegion tmp, tmp2(rgn);
271
272 tmp = tmp2;
273 tmp.translate(5, -3);
274
275 {
276 char buffer[1000];
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000277 size_t size = tmp.writeToMemory(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278 SkASSERT(size <= sizeof(buffer));
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000279 size_t size2 = tmp.writeToMemory(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000280 SkASSERT(size == size2);
281
282 SkRegion tmp3;
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000283 size2 = tmp3.readFromMemory(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000284 SkASSERT(size == size2);
285
286 SkASSERT(tmp3 == tmp);
287 }
288
289 rgn.translate(20, 30, &tmp);
290 SkASSERT(rgn.isEmpty() || tmp != rgn);
291 tmp.translate(-20, -30);
292 SkASSERT(tmp == rgn);
293 }
294
295 this->drawOrig(canvas, true);
296
297 SkPaint paint;
298 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
299 paint_rgn(canvas, rgn, paint);
300
301 paint.setStyle(SkPaint::kStroke_Style);
302 paint.setColor(color);
303 paint_rgn(canvas, rgn, paint);
304 }
305
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000306 void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000307 SkRegion rgn;
308 SkPath path;
309
310 this->build_rgn(&rgn, op);
311 rgn.getBoundaryPath(&path);
312
313 this->drawOrig(canvas, true);
314
315 SkPaint paint;
316
317 paint.setStyle(SkPaint::kFill_Style);
318 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
319 canvas->drawPath(path, paint);
320 paint.setColor(color);
321 paint.setStyle(SkPaint::kStroke_Style);
322 canvas->drawPath(path, paint);
323 }
324
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000325 virtual void onDrawContent(SkCanvas* canvas) {
caryclark@google.com02939ce2012-06-06 12:09:51 +0000326 if (false) { // avoid bit rot, suppress warning
327 test_strokerect(canvas);
328 return;
329 }
330 if (false) { // avoid bit rot, suppress warning
331 test_text(canvas);
332 return;
333 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334#ifdef SK_DEBUG
335 if (true) {
336 SkRegion a, b, c;
337 test_union_bug_1505668(&a, &b, &c);
338
339 if (false) { // draw the result of the test
340 SkPaint paint;
341
342 canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
343 paint.setColor(SK_ColorRED);
344 paint_rgn(canvas, a, paint);
345 paint.setColor(0x800000FF);
346 paint_rgn(canvas, b, paint);
347 paint.setColor(SK_ColorBLACK);
348 paint.setStyle(SkPaint::kStroke_Style);
349 // paint_rgn(canvas, c, paint);
350 return;
351 }
352 }
353#endif
reed@google.com4b5894c2012-05-02 18:03:32 +0000354 const SkPoint origins[] = {
355 { 30*SK_Scalar1, 50*SK_Scalar1 },
356 { 150*SK_Scalar1, 50*SK_Scalar1 },
357 };
358 this->drawPredicates(canvas, origins);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000359
360 static const struct {
361 SkColor fColor;
362 const char* fName;
363 SkRegion::Op fOp;
364 } gOps[] = {
365 { SK_ColorBLACK, "Difference", SkRegion::kDifference_Op },
366 { SK_ColorRED, "Intersect", SkRegion::kIntersect_Op },
367 { 0xFF008800, "Union", SkRegion::kUnion_Op },
368 { SK_ColorBLUE, "XOR", SkRegion::kXOR_Op }
369 };
370
371 SkPaint textPaint;
372 textPaint.setAntiAlias(true);
373 textPaint.setTextSize(SK_Scalar1*24);
374
375 this->drawOrig(canvas, false);
376 canvas->save();
377 canvas->translate(SkIntToScalar(200), 0);
378 this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK);
379 canvas->restore();
380
381 canvas->translate(0, SkIntToScalar(200));
382
senorblanco@chromium.org64cc5792011-05-19 19:58:58 +0000383 for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); op++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000384 canvas->drawText(gOps[op].fName, strlen(gOps[op].fName), SkIntToScalar(75), SkIntToScalar(50), textPaint);
385
386 this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
387
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000388 canvas->save();
389 canvas->translate(0, SkIntToScalar(200));
390 this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
391 canvas->restore();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000392
393 canvas->translate(SkIntToScalar(200), 0);
394 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000395 }
396
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000397 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
reed@android.com671cd652009-05-22 20:44:12 +0000398 return fRect.contains(SkScalarRound(x), SkScalarRound(y)) ? new Click(this) : NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000399 }
400
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000401 virtual bool onClick(Click* click) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000402 fRect.offset(click->fICurr.fX - click->fIPrev.fX,
403 click->fICurr.fY - click->fIPrev.fY);
reed@android.com671cd652009-05-22 20:44:12 +0000404 this->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000405 return true;
406 }
407
408private:
409 SkIRect fBase, fRect;
410
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000411 typedef SampleView INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000412};
413
414//////////////////////////////////////////////////////////////////////////////
415
416static SkView* MyFactory() { return new RegionView; }
417static SkViewRegister reg(MyFactory);
418