blob: 639203b8bc58a1a153e5e23b5236b43ff53d5889 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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 */
reed8a21c9f2016-03-08 18:50:00 -08007
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
bungemanb7069e92015-07-21 14:14:30 -070018#include <math.h>
19
reed@google.com4b5894c2012-05-02 18:03:32 +000020static void test_strokerect(SkCanvas* canvas) {
21 int width = 100;
22 int height = 100;
23
24 SkBitmap bitmap;
commit-bot@chromium.orga8c18312014-02-17 02:55:57 +000025 bitmap.allocPixels(SkImageInfo::MakeA8(width*2, height*2));
junov@google.comdbfac8a2012-12-06 21:47:40 +000026 bitmap.eraseColor(SK_ColorTRANSPARENT);
reed@google.com4b5894c2012-05-02 18:03:32 +000027
28 SkScalar dx = 20;
29 SkScalar dy = 20;
rmistry@google.comae933ce2012-08-23 18:19:56 +000030
reed@google.com4b5894c2012-05-02 18:03:32 +000031 SkPath path;
rmistry@google.comae933ce2012-08-23 18:19:56 +000032 path.addRect(0.0f, 0.0f,
33 SkIntToScalar(width), SkIntToScalar(height),
robertphillips@google.com4debcac2012-05-14 16:33:36 +000034 SkPath::kCW_Direction);
35 SkRect r = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
rmistry@google.comae933ce2012-08-23 18:19:56 +000036
reed@google.com4b5894c2012-05-02 18:03:32 +000037 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
junov@google.comdbfac8a2012-12-06 21:47:40 +000045 c.clear(SK_ColorTRANSPARENT);
reed@google.com4b5894c2012-05-02 18:03:32 +000046 c.drawRect(r, paint);
halcanary96fcdcc2015-08-27 07:41:13 -070047 canvas->drawBitmap(bitmap, 0, 0, nullptr);
reed@google.com4b5894c2012-05-02 18:03:32 +000048
49 // use the path
junov@google.comdbfac8a2012-12-06 21:47:40 +000050 c.clear(SK_ColorTRANSPARENT);
reed@google.com4b5894c2012-05-02 18:03:32 +000051 c.drawPath(path, paint);
halcanary96fcdcc2015-08-27 07:41:13 -070052 canvas->drawBitmap(bitmap, SkIntToScalar(2*width), 0, nullptr);
reed@google.com4b5894c2012-05-02 18:03:32 +000053}
54
55static 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;
rmistry@google.comae933ce2012-08-23 18:19:56 +000061
reed@google.com4b5894c2012-05-02 18:03:32 +000062 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
halcanary96fcdcc2015-08-27 07:41:13 -070069 canvas->saveLayer(&bounds, nullptr);
reed@google.com4b5894c2012-05-02 18:03:32 +000070 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.
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000080 const SkScalar pos[] = { 0, 0.9f, SK_Scalar1 };
reed@google.com4b5894c2012-05-02 18:03:32 +000081
reed@google.com4b5894c2012-05-02 18:03:32 +000082 SkPaint p;
reed8a21c9f2016-03-08 18:50:00 -080083 p.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 3, SkShader::kClamp_TileMode));
reed@google.com4b5894c2012-05-02 18:03:32 +000084 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 };
reed8a21c9f2016-03-08 18:50:00 -0800107 paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos,
reed@google.com4b5894c2012-05-02 18:03:32 +0000108 SK_ARRAY_COUNT(colors),
reed8a21c9f2016-03-08 18:50:00 -0800109 SkShader::kClamp_TileMode));
reed@google.com4b5894c2012-05-02 18:03:32 +0000110 canvas->drawText(str, len, x, y, paint);
111
112 y += 20;
halcanary96fcdcc2015-08-27 07:41:13 -0700113 paint.setShader(nullptr);
reed@google.com4b5894c2012-05-02 18:03:32 +0000114 drawFadingText(canvas, str, len, x, y, paint);
115}
116
reed@android.com8a1c16f2008-12-17 15:59:43 +0000117#ifdef SK_DEBUG
118static void make_rgn(SkRegion* rgn, int left, int top, int right, int bottom,
reed@google.com7fa2a652014-01-27 13:42:58 +0000119 int count, int32_t runs[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000120 SkIRect r;
121 r.set(left, top, right, bottom);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000122
reed@android.com8a1c16f2008-12-17 15:59:43 +0000123 rgn->debugSetRuns(runs, count);
124 SkASSERT(rgn->getBounds() == r);
125}
126
127static void test_union_bug_1505668(SkRegion* ra, SkRegion* rb, SkRegion* rc) {
128 static int32_t dataA[] = {
reed@google.com4b5894c2012-05-02 18:03:32 +0000129 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
reed@android.com8a1c16f2008-12-17 15:59:43 +0000137 };
138 make_rgn(ra, 0, 1, 315, 1496, SK_ARRAY_COUNT(dataA), dataA);
139
140 static int32_t dataB[] = {
reed@google.com4b5894c2012-05-02 18:03:32 +0000141 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
reed@android.com8a1c16f2008-12-17 15:59:43 +0000150 };
151 make_rgn(rb, 112, 182, 240, 260, SK_ARRAY_COUNT(dataB), dataB);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000152
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153 rc->op(*ra, *rb, SkRegion::kUnion_Op);
154}
155#endif
156
reed@android.comf76bacf2009-05-13 14:00:33 +0000157static 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
164static 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
176static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn,
177 const SkPaint& paint) {
178 SkRegion scaled;
179 scale_rgn(&scaled, rgn, 0.5f);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000180
reed@android.comf76bacf2009-05-13 14:00:33 +0000181 SkRegion::Iterator iter(rgn);
182
reed@android.com8a1c16f2008-12-17 15:59:43 +0000183 for (; !iter.done(); iter.next())
184 {
185 SkRect r;
186 r.set(iter.rect());
187 canvas->drawRect(r, paint);
188 }
189}
190
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000191class RegionView : public SampleView {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192public:
rmistry@google.comae933ce2012-08-23 18:19:56 +0000193 RegionView() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194 fBase.set(100, 100, 150, 150);
195 fRect = fBase;
196 fRect.inset(5, 5);
197 fRect.offset(25, 25);
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000198 this->setBGColor(0xFFDDDDDD);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199 }
200
reed@google.com4b5894c2012-05-02 18:03:32 +0000201 void build_base_rgn(SkRegion* rgn) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202 rgn->setRect(fBase);
203 SkIRect r = fBase;
204 r.offset(75, 20);
205 rgn->op(r, SkRegion::kUnion_Op);
reed@google.com4b5894c2012-05-02 18:03:32 +0000206 }
207
208 void build_rgn(SkRegion* rgn, SkRegion::Op op) {
209 build_base_rgn(rgn);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210 rgn->op(fRect, op);
211 }
212
213
214protected:
215 // overrides from SkEventSink
mtklein36352bf2015-03-25 18:17:31 -0700216 bool onQuery(SkEvent* evt) override {
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000217 if (SampleCode::TitleQ(*evt)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 SampleCode::TitleR(evt, "Regions");
219 return true;
220 }
221 return this->INHERITED::onQuery(evt);
222 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000223
reed@google.com4b5894c2012-05-02 18:03:32 +0000224 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->drawText(text, strlen(text), loc.fX, loc.fY, paint);
231 }
232
233 void drawPredicates(SkCanvas* canvas, const SkPoint pts[]) {
234 SkRegion rgn;
235 build_base_rgn(&rgn);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000236
reed@google.com4b5894c2012-05-02 18:03:32 +0000237 drawstr(canvas, "Intersects", pts[0], rgn.intersects(fRect));
238 drawstr(canvas, "Contains", pts[1], rgn.contains(fRect));
239 }
240
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000241 void drawOrig(SkCanvas* canvas, bool bg) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242 SkRect r;
243 SkPaint paint;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000244
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245 paint.setStyle(SkPaint::kStroke_Style);
246 if (bg)
247 paint.setColor(0xFFBBBBBB);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000248
reed@google.com4b5894c2012-05-02 18:03:32 +0000249 SkRegion rgn;
250 build_base_rgn(&rgn);
251 paint_rgn(canvas, rgn, paint);
252
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253 r.set(fRect);
254 canvas->drawRect(r, paint);
255 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000256
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000257 void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000258 SkRegion rgn;
259
260 this->build_rgn(&rgn, op);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000261
reed@android.com8a1c16f2008-12-17 15:59:43 +0000262 {
263 SkRegion tmp, tmp2(rgn);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000264
reed@android.com8a1c16f2008-12-17 15:59:43 +0000265 tmp = tmp2;
266 tmp.translate(5, -3);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000267
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268 {
269 char buffer[1000];
halcanary96fcdcc2015-08-27 07:41:13 -0700270 SkDEBUGCODE(size_t size = ) tmp.writeToMemory(nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271 SkASSERT(size <= sizeof(buffer));
humper@google.com0e515772013-01-07 19:54:40 +0000272 SkDEBUGCODE(size_t size2 = ) tmp.writeToMemory(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000273 SkASSERT(size == size2);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000274
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275 SkRegion tmp3;
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000276 SkDEBUGCODE(size2 = ) tmp3.readFromMemory(buffer, 1000);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277 SkASSERT(size == size2);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000278
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279 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 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000298
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000299 void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000300 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 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000317
mtklein36352bf2015-03-25 18:17:31 -0700318 void onDrawContent(SkCanvas* canvas) override {
caryclark@google.com02939ce2012-06-06 12:09:51 +0000319 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 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000327#ifdef SK_DEBUG
328 if (true) {
329 SkRegion a, b, c;
330 test_union_bug_1505668(&a, &b, &c);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000331
reed@android.com8a1c16f2008-12-17 15:59:43 +0000332 if (false) { // draw the result of the test
333 SkPaint paint;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000334
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335 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
reed@google.com4b5894c2012-05-02 18:03:32 +0000347 const SkPoint origins[] = {
348 { 30*SK_Scalar1, 50*SK_Scalar1 },
349 { 150*SK_Scalar1, 50*SK_Scalar1 },
350 };
351 this->drawPredicates(canvas, origins);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352
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();
rmistry@google.comae933ce2012-08-23 18:19:56 +0000373
reed@android.com8a1c16f2008-12-17 15:59:43 +0000374 canvas->translate(0, SkIntToScalar(200));
375
senorblanco@chromium.org64cc5792011-05-19 19:58:58 +0000376 for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); op++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377 canvas->drawText(gOps[op].fName, strlen(gOps[op].fName), SkIntToScalar(75), SkIntToScalar(50), textPaint);
378
379 this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
380
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000381 canvas->save();
382 canvas->translate(0, SkIntToScalar(200));
383 this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
384 canvas->restore();
rmistry@google.comae933ce2012-08-23 18:19:56 +0000385
reed@android.com8a1c16f2008-12-17 15:59:43 +0000386 canvas->translate(SkIntToScalar(200), 0);
387 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000388 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000389
mike@reedtribe.orgdd0c3a52013-02-18 21:52:43 +0000390 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y,
mtklein36352bf2015-03-25 18:17:31 -0700391 unsigned modi) override {
reed@google.come1ca7052013-12-17 19:22:07 +0000392 return fRect.contains(SkScalarRoundToInt(x),
halcanary96fcdcc2015-08-27 07:41:13 -0700393 SkScalarRoundToInt(y)) ? new Click(this) : nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000394 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000395
mtklein36352bf2015-03-25 18:17:31 -0700396 bool onClick(Click* click) override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000397 fRect.offset(click->fICurr.fX - click->fIPrev.fX,
398 click->fICurr.fY - click->fIPrev.fY);
halcanary96fcdcc2015-08-27 07:41:13 -0700399 this->inval(nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000400 return true;
401 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000402
reed@android.com8a1c16f2008-12-17 15:59:43 +0000403private:
404 SkIRect fBase, fRect;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000405
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000406 typedef SampleView INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000407};
408
409//////////////////////////////////////////////////////////////////////////////
410
411static SkView* MyFactory() { return new RegionView; }
412static SkViewRegister reg(MyFactory);