blob: 3c5fc2e35cf0ac445c387b6f0373ac959b2b6cfc [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;
commit-bot@chromium.orga8c18312014-02-17 02:55:57 +000023 bitmap.allocPixels(SkImageInfo::MakeA8(width*2, height*2));
junov@google.comdbfac8a2012-12-06 21:47:40 +000024 bitmap.eraseColor(SK_ColorTRANSPARENT);
reed@google.com4b5894c2012-05-02 18:03:32 +000025
26 SkScalar dx = 20;
27 SkScalar dy = 20;
rmistry@google.comae933ce2012-08-23 18:19:56 +000028
reed@google.com4b5894c2012-05-02 18:03:32 +000029 SkPath path;
rmistry@google.comae933ce2012-08-23 18:19:56 +000030 path.addRect(0.0f, 0.0f,
31 SkIntToScalar(width), SkIntToScalar(height),
robertphillips@google.com4debcac2012-05-14 16:33:36 +000032 SkPath::kCW_Direction);
33 SkRect r = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
rmistry@google.comae933ce2012-08-23 18:19:56 +000034
reed@google.com4b5894c2012-05-02 18:03:32 +000035 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
junov@google.comdbfac8a2012-12-06 21:47:40 +000043 c.clear(SK_ColorTRANSPARENT);
reed@google.com4b5894c2012-05-02 18:03:32 +000044 c.drawRect(r, paint);
45 canvas->drawBitmap(bitmap, 0, 0, NULL);
46
47 // use the path
junov@google.comdbfac8a2012-12-06 21:47:40 +000048 c.clear(SK_ColorTRANSPARENT);
reed@google.com4b5894c2012-05-02 18:03:32 +000049 c.drawPath(path, paint);
robertphillips@google.com4debcac2012-05-14 16:33:36 +000050 canvas->drawBitmap(bitmap, SkIntToScalar(2*width), 0, NULL);
reed@google.com4b5894c2012-05-02 18:03:32 +000051}
52
53static 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;
rmistry@google.comae933ce2012-08-23 18:19:56 +000059
reed@google.com4b5894c2012-05-02 18:03:32 +000060 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.
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000078 const SkScalar pos[] = { 0, 0.9f, SK_Scalar1 };
reed@google.com4b5894c2012-05-02 18:03:32 +000079
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
90static void test_text(SkCanvas* canvas) {
91 SkPaint paint;
92 paint.setAntiAlias(true);
93 paint.setTextSize(20);
rmistry@google.comae933ce2012-08-23 18:19:56 +000094
reed@google.com4b5894c2012-05-02 18:03:32 +000095 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
reed@android.comf2b98d62010-12-20 18:26:13 +0000118#ifdef SK_BUILD_FOR_WIN
119// windows doesn't have roundf
120inline float roundf(float x) { return (x-floor(x))>0.5 ? ceil(x) : floor(x); }
121#endif
122
reed@android.com8a1c16f2008-12-17 15:59:43 +0000123#ifdef SK_DEBUG
124static void make_rgn(SkRegion* rgn, int left, int top, int right, int bottom,
reed@google.com7fa2a652014-01-27 13:42:58 +0000125 int count, int32_t runs[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126 SkIRect r;
127 r.set(left, top, right, bottom);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000128
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129 rgn->debugSetRuns(runs, count);
130 SkASSERT(rgn->getBounds() == r);
131}
132
133static void test_union_bug_1505668(SkRegion* ra, SkRegion* rb, SkRegion* rc) {
134 static int32_t dataA[] = {
reed@google.com4b5894c2012-05-02 18:03:32 +0000135 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
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143 };
144 make_rgn(ra, 0, 1, 315, 1496, SK_ARRAY_COUNT(dataA), dataA);
145
146 static int32_t dataB[] = {
reed@google.com4b5894c2012-05-02 18:03:32 +0000147 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
reed@android.com8a1c16f2008-12-17 15:59:43 +0000156 };
157 make_rgn(rb, 112, 182, 240, 260, SK_ARRAY_COUNT(dataB), dataB);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000158
reed@android.com8a1c16f2008-12-17 15:59:43 +0000159 rc->op(*ra, *rb, SkRegion::kUnion_Op);
160}
161#endif
162
reed@android.comf76bacf2009-05-13 14:00:33 +0000163static 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
170static 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
182static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn,
183 const SkPaint& paint) {
184 SkRegion scaled;
185 scale_rgn(&scaled, rgn, 0.5f);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000186
reed@android.comf76bacf2009-05-13 14:00:33 +0000187 SkRegion::Iterator iter(rgn);
188
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189 for (; !iter.done(); iter.next())
190 {
191 SkRect r;
192 r.set(iter.rect());
193 canvas->drawRect(r, paint);
194 }
195}
196
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000197class RegionView : public SampleView {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198public:
rmistry@google.comae933ce2012-08-23 18:19:56 +0000199 RegionView() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200 fBase.set(100, 100, 150, 150);
201 fRect = fBase;
202 fRect.inset(5, 5);
203 fRect.offset(25, 25);
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000204 this->setBGColor(0xFFDDDDDD);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205 }
206
reed@google.com4b5894c2012-05-02 18:03:32 +0000207 void build_base_rgn(SkRegion* rgn) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208 rgn->setRect(fBase);
209 SkIRect r = fBase;
210 r.offset(75, 20);
211 rgn->op(r, SkRegion::kUnion_Op);
reed@google.com4b5894c2012-05-02 18:03:32 +0000212 }
213
214 void build_rgn(SkRegion* rgn, SkRegion::Op op) {
215 build_base_rgn(rgn);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 rgn->op(fRect, op);
217 }
218
219
220protected:
221 // overrides from SkEventSink
mtklein36352bf2015-03-25 18:17:31 -0700222 bool onQuery(SkEvent* evt) override {
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000223 if (SampleCode::TitleQ(*evt)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224 SampleCode::TitleR(evt, "Regions");
225 return true;
226 }
227 return this->INHERITED::onQuery(evt);
228 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000229
reed@google.com4b5894c2012-05-02 18:03:32 +0000230 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
239 void drawPredicates(SkCanvas* canvas, const SkPoint pts[]) {
240 SkRegion rgn;
241 build_base_rgn(&rgn);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000242
reed@google.com4b5894c2012-05-02 18:03:32 +0000243 drawstr(canvas, "Intersects", pts[0], rgn.intersects(fRect));
244 drawstr(canvas, "Contains", pts[1], rgn.contains(fRect));
245 }
246
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000247 void drawOrig(SkCanvas* canvas, bool bg) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000248 SkRect r;
249 SkPaint paint;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000250
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 paint.setStyle(SkPaint::kStroke_Style);
252 if (bg)
253 paint.setColor(0xFFBBBBBB);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000254
reed@google.com4b5894c2012-05-02 18:03:32 +0000255 SkRegion rgn;
256 build_base_rgn(&rgn);
257 paint_rgn(canvas, rgn, paint);
258
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259 r.set(fRect);
260 canvas->drawRect(r, paint);
261 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000262
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000263 void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000264 SkRegion rgn;
265
266 this->build_rgn(&rgn, op);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000267
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268 {
269 SkRegion tmp, tmp2(rgn);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000270
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271 tmp = tmp2;
272 tmp.translate(5, -3);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000273
reed@android.com8a1c16f2008-12-17 15:59:43 +0000274 {
275 char buffer[1000];
humper@google.com0e515772013-01-07 19:54:40 +0000276 SkDEBUGCODE(size_t size = ) tmp.writeToMemory(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277 SkASSERT(size <= sizeof(buffer));
humper@google.com0e515772013-01-07 19:54:40 +0000278 SkDEBUGCODE(size_t size2 = ) tmp.writeToMemory(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279 SkASSERT(size == size2);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000280
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281 SkRegion tmp3;
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000282 SkDEBUGCODE(size2 = ) tmp3.readFromMemory(buffer, 1000);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000283 SkASSERT(size == size2);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000284
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 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 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000304
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000305 void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000306 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 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000323
mtklein36352bf2015-03-25 18:17:31 -0700324 void onDrawContent(SkCanvas* canvas) override {
caryclark@google.com02939ce2012-06-06 12:09:51 +0000325 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 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000333#ifdef SK_DEBUG
334 if (true) {
335 SkRegion a, b, c;
336 test_union_bug_1505668(&a, &b, &c);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000337
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338 if (false) { // draw the result of the test
339 SkPaint paint;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000340
reed@android.com8a1c16f2008-12-17 15:59:43 +0000341 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
reed@google.com4b5894c2012-05-02 18:03:32 +0000353 const SkPoint origins[] = {
354 { 30*SK_Scalar1, 50*SK_Scalar1 },
355 { 150*SK_Scalar1, 50*SK_Scalar1 },
356 };
357 this->drawPredicates(canvas, origins);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358
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();
rmistry@google.comae933ce2012-08-23 18:19:56 +0000379
reed@android.com8a1c16f2008-12-17 15:59:43 +0000380 canvas->translate(0, SkIntToScalar(200));
381
senorblanco@chromium.org64cc5792011-05-19 19:58:58 +0000382 for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); op++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383 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
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000387 canvas->save();
388 canvas->translate(0, SkIntToScalar(200));
389 this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
390 canvas->restore();
rmistry@google.comae933ce2012-08-23 18:19:56 +0000391
reed@android.com8a1c16f2008-12-17 15:59:43 +0000392 canvas->translate(SkIntToScalar(200), 0);
393 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000394 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000395
mike@reedtribe.orgdd0c3a52013-02-18 21:52:43 +0000396 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y,
mtklein36352bf2015-03-25 18:17:31 -0700397 unsigned modi) override {
reed@google.come1ca7052013-12-17 19:22:07 +0000398 return fRect.contains(SkScalarRoundToInt(x),
399 SkScalarRoundToInt(y)) ? new Click(this) : NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000400 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000401
mtklein36352bf2015-03-25 18:17:31 -0700402 bool onClick(Click* click) override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000403 fRect.offset(click->fICurr.fX - click->fIPrev.fX,
404 click->fICurr.fY - click->fIPrev.fY);
reed@android.com671cd652009-05-22 20:44:12 +0000405 this->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000406 return true;
407 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000408
reed@android.com8a1c16f2008-12-17 15:59:43 +0000409private:
410 SkIRect fBase, fRect;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000411
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000412 typedef SampleView INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000413};
414
415//////////////////////////////////////////////////////////////////////////////
416
417static SkView* MyFactory() { return new RegionView; }
418static SkViewRegister reg(MyFactory);