blob: 82883c69f0a9affd0ffdc817784ea676232edf2c [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"
Mike Reed75ae4212018-01-23 11:24:08 -050010#include "SkBitmap.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000011#include "SkCanvas.h"
12#include "SkGradientShader.h"
13#include "SkPath.h"
14#include "SkRegion.h"
15#include "SkShader.h"
16#include "SkUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017
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));
reed374772b2016-10-05 17:33:02 -070084 p.setBlendMode(SkBlendMode::kDstIn);
reed@google.com4b5894c2012-05-02 18:03:32 +000085 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.comf76bacf2009-05-13 14:00:33 +0000117static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
118 dst->fLeft = (int)::roundf(src.fLeft * scale);
119 dst->fTop = (int)::roundf(src.fTop * scale);
120 dst->fRight = (int)::roundf(src.fRight * scale);
121 dst->fBottom = (int)::roundf(src.fBottom * scale);
122}
123
124static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
125 SkRegion tmp;
126 SkRegion::Iterator iter(src);
127
128 for (; !iter.done(); iter.next()) {
129 SkIRect r;
130 scale_rect(&r, iter.rect(), scale);
131 tmp.op(r, SkRegion::kUnion_Op);
132 }
133 dst->swap(tmp);
134}
135
136static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn,
137 const SkPaint& paint) {
138 SkRegion scaled;
139 scale_rgn(&scaled, rgn, 0.5f);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000140
reed@android.comf76bacf2009-05-13 14:00:33 +0000141 SkRegion::Iterator iter(rgn);
142
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143 for (; !iter.done(); iter.next())
144 {
145 SkRect r;
146 r.set(iter.rect());
147 canvas->drawRect(r, paint);
148 }
149}
150
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000151class RegionView : public SampleView {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152public:
rmistry@google.comae933ce2012-08-23 18:19:56 +0000153 RegionView() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154 fBase.set(100, 100, 150, 150);
155 fRect = fBase;
156 fRect.inset(5, 5);
157 fRect.offset(25, 25);
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000158 this->setBGColor(0xFFDDDDDD);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000159 }
160
reed@google.com4b5894c2012-05-02 18:03:32 +0000161 void build_base_rgn(SkRegion* rgn) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000162 rgn->setRect(fBase);
163 SkIRect r = fBase;
164 r.offset(75, 20);
165 rgn->op(r, SkRegion::kUnion_Op);
reed@google.com4b5894c2012-05-02 18:03:32 +0000166 }
167
168 void build_rgn(SkRegion* rgn, SkRegion::Op op) {
169 build_base_rgn(rgn);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170 rgn->op(fRect, op);
171 }
172
173
174protected:
175 // overrides from SkEventSink
mtklein36352bf2015-03-25 18:17:31 -0700176 bool onQuery(SkEvent* evt) override {
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000177 if (SampleCode::TitleQ(*evt)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178 SampleCode::TitleR(evt, "Regions");
179 return true;
180 }
181 return this->INHERITED::onQuery(evt);
182 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000183
reed@google.com4b5894c2012-05-02 18:03:32 +0000184 static void drawstr(SkCanvas* canvas, const char text[], const SkPoint& loc,
185 bool hilite) {
186 SkPaint paint;
187 paint.setAntiAlias(true);
188 paint.setTextSize(SkIntToScalar(20));
189 paint.setColor(hilite ? SK_ColorRED : 0x40FF0000);
Cary Clark2a475ea2017-04-28 15:35:12 -0400190 canvas->drawString(text, loc.fX, loc.fY, paint);
reed@google.com4b5894c2012-05-02 18:03:32 +0000191 }
192
193 void drawPredicates(SkCanvas* canvas, const SkPoint pts[]) {
194 SkRegion rgn;
195 build_base_rgn(&rgn);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000196
reed@google.com4b5894c2012-05-02 18:03:32 +0000197 drawstr(canvas, "Intersects", pts[0], rgn.intersects(fRect));
198 drawstr(canvas, "Contains", pts[1], rgn.contains(fRect));
199 }
200
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000201 void drawOrig(SkCanvas* canvas, bool bg) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202 SkRect r;
203 SkPaint paint;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000204
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205 paint.setStyle(SkPaint::kStroke_Style);
206 if (bg)
207 paint.setColor(0xFFBBBBBB);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000208
reed@google.com4b5894c2012-05-02 18:03:32 +0000209 SkRegion rgn;
210 build_base_rgn(&rgn);
211 paint_rgn(canvas, rgn, paint);
212
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213 r.set(fRect);
214 canvas->drawRect(r, paint);
215 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000216
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000217 void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 SkRegion rgn;
219
220 this->build_rgn(&rgn, op);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000221
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 {
223 SkRegion tmp, tmp2(rgn);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000224
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 tmp = tmp2;
226 tmp.translate(5, -3);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000227
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228 {
229 char buffer[1000];
halcanary96fcdcc2015-08-27 07:41:13 -0700230 SkDEBUGCODE(size_t size = ) tmp.writeToMemory(nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231 SkASSERT(size <= sizeof(buffer));
humper@google.com0e515772013-01-07 19:54:40 +0000232 SkDEBUGCODE(size_t size2 = ) tmp.writeToMemory(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 SkASSERT(size == size2);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000234
reed@android.com8a1c16f2008-12-17 15:59:43 +0000235 SkRegion tmp3;
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000236 SkDEBUGCODE(size2 = ) tmp3.readFromMemory(buffer, 1000);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237 SkASSERT(size == size2);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000238
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 SkASSERT(tmp3 == tmp);
240 }
241
242 rgn.translate(20, 30, &tmp);
243 SkASSERT(rgn.isEmpty() || tmp != rgn);
244 tmp.translate(-20, -30);
245 SkASSERT(tmp == rgn);
246 }
247
248 this->drawOrig(canvas, true);
249
250 SkPaint paint;
251 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
252 paint_rgn(canvas, rgn, paint);
253
254 paint.setStyle(SkPaint::kStroke_Style);
255 paint.setColor(color);
256 paint_rgn(canvas, rgn, paint);
257 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000258
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000259 void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000260 SkRegion rgn;
261 SkPath path;
262
263 this->build_rgn(&rgn, op);
264 rgn.getBoundaryPath(&path);
265
266 this->drawOrig(canvas, true);
267
268 SkPaint paint;
269
270 paint.setStyle(SkPaint::kFill_Style);
271 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
272 canvas->drawPath(path, paint);
273 paint.setColor(color);
274 paint.setStyle(SkPaint::kStroke_Style);
275 canvas->drawPath(path, paint);
276 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000277
mtklein36352bf2015-03-25 18:17:31 -0700278 void onDrawContent(SkCanvas* canvas) override {
caryclark@google.com02939ce2012-06-06 12:09:51 +0000279 if (false) { // avoid bit rot, suppress warning
280 test_strokerect(canvas);
281 return;
282 }
283 if (false) { // avoid bit rot, suppress warning
284 test_text(canvas);
285 return;
286 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000287
reed@google.com4b5894c2012-05-02 18:03:32 +0000288 const SkPoint origins[] = {
289 { 30*SK_Scalar1, 50*SK_Scalar1 },
290 { 150*SK_Scalar1, 50*SK_Scalar1 },
291 };
292 this->drawPredicates(canvas, origins);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000293
294 static const struct {
295 SkColor fColor;
296 const char* fName;
297 SkRegion::Op fOp;
298 } gOps[] = {
299 { SK_ColorBLACK, "Difference", SkRegion::kDifference_Op },
300 { SK_ColorRED, "Intersect", SkRegion::kIntersect_Op },
301 { 0xFF008800, "Union", SkRegion::kUnion_Op },
302 { SK_ColorBLUE, "XOR", SkRegion::kXOR_Op }
303 };
304
305 SkPaint textPaint;
306 textPaint.setAntiAlias(true);
307 textPaint.setTextSize(SK_Scalar1*24);
308
309 this->drawOrig(canvas, false);
310 canvas->save();
311 canvas->translate(SkIntToScalar(200), 0);
312 this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK);
313 canvas->restore();
rmistry@google.comae933ce2012-08-23 18:19:56 +0000314
reed@android.com8a1c16f2008-12-17 15:59:43 +0000315 canvas->translate(0, SkIntToScalar(200));
316
senorblanco@chromium.org64cc5792011-05-19 19:58:58 +0000317 for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); op++) {
Cary Clark2a475ea2017-04-28 15:35:12 -0400318 canvas->drawString(gOps[op].fName, SkIntToScalar(75), SkIntToScalar(50), textPaint);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000319
320 this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
321
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000322 canvas->save();
323 canvas->translate(0, SkIntToScalar(200));
324 this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
325 canvas->restore();
rmistry@google.comae933ce2012-08-23 18:19:56 +0000326
reed@android.com8a1c16f2008-12-17 15:59:43 +0000327 canvas->translate(SkIntToScalar(200), 0);
328 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000330
mike@reedtribe.orgdd0c3a52013-02-18 21:52:43 +0000331 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y,
mtklein36352bf2015-03-25 18:17:31 -0700332 unsigned modi) override {
reed@google.come1ca7052013-12-17 19:22:07 +0000333 return fRect.contains(SkScalarRoundToInt(x),
halcanary96fcdcc2015-08-27 07:41:13 -0700334 SkScalarRoundToInt(y)) ? new Click(this) : nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000336
mtklein36352bf2015-03-25 18:17:31 -0700337 bool onClick(Click* click) override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338 fRect.offset(click->fICurr.fX - click->fIPrev.fX,
339 click->fICurr.fY - click->fIPrev.fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340 return true;
341 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000342
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343private:
344 SkIRect fBase, fRect;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000345
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000346 typedef SampleView INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000347};
348
349//////////////////////////////////////////////////////////////////////////////
350
351static SkView* MyFactory() { return new RegionView; }
352static SkViewRegister reg(MyFactory);