blob: a9526face89bd5c3011857902306a8e93007ad83 [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
Ben Wagnerb2c4ea62018-08-08 11:36:17 -04008#include "Sample.h"
Mike Reed75ae4212018-01-23 11:24:08 -05009#include "SkBitmap.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkCanvas.h"
11#include "SkGradientShader.h"
12#include "SkPath.h"
13#include "SkRegion.h"
14#include "SkShader.h"
Hal Canaryea60b952018-08-21 11:45:46 -040015#include "SkUTF.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016
bungemanb7069e92015-07-21 14:14:30 -070017#include <math.h>
18
reed@google.com4b5894c2012-05-02 18:03:32 +000019static void test_strokerect(SkCanvas* canvas) {
20 int width = 100;
21 int height = 100;
22
23 SkBitmap bitmap;
commit-bot@chromium.orga8c18312014-02-17 02:55:57 +000024 bitmap.allocPixels(SkImageInfo::MakeA8(width*2, height*2));
junov@google.comdbfac8a2012-12-06 21:47:40 +000025 bitmap.eraseColor(SK_ColorTRANSPARENT);
reed@google.com4b5894c2012-05-02 18:03:32 +000026
27 SkScalar dx = 20;
28 SkScalar dy = 20;
rmistry@google.comae933ce2012-08-23 18:19:56 +000029
reed@google.com4b5894c2012-05-02 18:03:32 +000030 SkPath path;
rmistry@google.comae933ce2012-08-23 18:19:56 +000031 path.addRect(0.0f, 0.0f,
32 SkIntToScalar(width), SkIntToScalar(height),
robertphillips@google.com4debcac2012-05-14 16:33:36 +000033 SkPath::kCW_Direction);
34 SkRect r = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
rmistry@google.comae933ce2012-08-23 18:19:56 +000035
reed@google.com4b5894c2012-05-02 18:03:32 +000036 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
junov@google.comdbfac8a2012-12-06 21:47:40 +000044 c.clear(SK_ColorTRANSPARENT);
reed@google.com4b5894c2012-05-02 18:03:32 +000045 c.drawRect(r, paint);
halcanary96fcdcc2015-08-27 07:41:13 -070046 canvas->drawBitmap(bitmap, 0, 0, nullptr);
reed@google.com4b5894c2012-05-02 18:03:32 +000047
48 // use the path
junov@google.comdbfac8a2012-12-06 21:47:40 +000049 c.clear(SK_ColorTRANSPARENT);
reed@google.com4b5894c2012-05-02 18:03:32 +000050 c.drawPath(path, paint);
halcanary96fcdcc2015-08-27 07:41:13 -070051 canvas->drawBitmap(bitmap, SkIntToScalar(2*width), 0, nullptr);
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;
Mike Reedb5784ac2018-11-12 09:35:15 -050059 SkFontMetrics fm;
rmistry@google.comae933ce2012-08-23 18:19:56 +000060
reed@google.com4b5894c2012-05-02 18:03:32 +000061 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
halcanary96fcdcc2015-08-27 07:41:13 -070068 canvas->saveLayer(&bounds, nullptr);
reed@google.com4b5894c2012-05-02 18:03:32 +000069 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.
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000079 const SkScalar pos[] = { 0, 0.9f, SK_Scalar1 };
reed@google.com4b5894c2012-05-02 18:03:32 +000080
reed@google.com4b5894c2012-05-02 18:03:32 +000081 SkPaint p;
reed8a21c9f2016-03-08 18:50:00 -080082 p.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 3, SkShader::kClamp_TileMode));
reed374772b2016-10-05 17:33:02 -070083 p.setBlendMode(SkBlendMode::kDstIn);
reed@google.com4b5894c2012-05-02 18:03:32 +000084 canvas->drawRect(bounds, p);
85
86 canvas->restore();
87}
88
89static void test_text(SkCanvas* canvas) {
90 SkPaint paint;
91 paint.setAntiAlias(true);
92 paint.setTextSize(20);
rmistry@google.comae933ce2012-08-23 18:19:56 +000093
reed@google.com4b5894c2012-05-02 18:03:32 +000094 const char* str = "Hamburgefons";
95 size_t len = strlen(str);
96 SkScalar x = 20;
97 SkScalar y = 20;
98
99 canvas->drawText(str, len, x, y, paint);
100
101 y += 20;
102
103 const SkPoint pts[] = { { x, y }, { x + paint.measureText(str, len), y } };
104 const SkColor colors[] = { SK_ColorBLACK, SK_ColorBLACK, 0 };
105 const SkScalar pos[] = { 0, 0.9f, 1 };
reed8a21c9f2016-03-08 18:50:00 -0800106 paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos,
reed@google.com4b5894c2012-05-02 18:03:32 +0000107 SK_ARRAY_COUNT(colors),
reed8a21c9f2016-03-08 18:50:00 -0800108 SkShader::kClamp_TileMode));
reed@google.com4b5894c2012-05-02 18:03:32 +0000109 canvas->drawText(str, len, x, y, paint);
110
111 y += 20;
halcanary96fcdcc2015-08-27 07:41:13 -0700112 paint.setShader(nullptr);
reed@google.com4b5894c2012-05-02 18:03:32 +0000113 drawFadingText(canvas, str, len, x, y, paint);
114}
115
reed@android.comf76bacf2009-05-13 14:00:33 +0000116static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
117 dst->fLeft = (int)::roundf(src.fLeft * scale);
118 dst->fTop = (int)::roundf(src.fTop * scale);
119 dst->fRight = (int)::roundf(src.fRight * scale);
120 dst->fBottom = (int)::roundf(src.fBottom * scale);
121}
122
123static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
124 SkRegion tmp;
125 SkRegion::Iterator iter(src);
126
127 for (; !iter.done(); iter.next()) {
128 SkIRect r;
129 scale_rect(&r, iter.rect(), scale);
130 tmp.op(r, SkRegion::kUnion_Op);
131 }
132 dst->swap(tmp);
133}
134
135static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn,
136 const SkPaint& paint) {
137 SkRegion scaled;
138 scale_rgn(&scaled, rgn, 0.5f);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000139
reed@android.comf76bacf2009-05-13 14:00:33 +0000140 SkRegion::Iterator iter(rgn);
141
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142 for (; !iter.done(); iter.next())
143 {
144 SkRect r;
145 r.set(iter.rect());
146 canvas->drawRect(r, paint);
147 }
148}
149
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400150class RegionView : public Sample {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000151public:
rmistry@google.comae933ce2012-08-23 18:19:56 +0000152 RegionView() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153 fBase.set(100, 100, 150, 150);
154 fRect = fBase;
155 fRect.inset(5, 5);
156 fRect.offset(25, 25);
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000157 this->setBGColor(0xFFDDDDDD);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000158 }
159
reed@google.com4b5894c2012-05-02 18:03:32 +0000160 void build_base_rgn(SkRegion* rgn) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161 rgn->setRect(fBase);
162 SkIRect r = fBase;
163 r.offset(75, 20);
164 rgn->op(r, SkRegion::kUnion_Op);
reed@google.com4b5894c2012-05-02 18:03:32 +0000165 }
166
167 void build_rgn(SkRegion* rgn, SkRegion::Op op) {
168 build_base_rgn(rgn);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169 rgn->op(fRect, op);
170 }
171
172
173protected:
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400174 bool onQuery(Sample::Event* evt) override {
175 if (Sample::TitleQ(*evt)) {
176 Sample::TitleR(evt, "Regions");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 return true;
178 }
179 return this->INHERITED::onQuery(evt);
180 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000181
reed@google.com4b5894c2012-05-02 18:03:32 +0000182 static void drawstr(SkCanvas* canvas, const char text[], const SkPoint& loc,
183 bool hilite) {
184 SkPaint paint;
185 paint.setAntiAlias(true);
186 paint.setTextSize(SkIntToScalar(20));
187 paint.setColor(hilite ? SK_ColorRED : 0x40FF0000);
Cary Clark2a475ea2017-04-28 15:35:12 -0400188 canvas->drawString(text, loc.fX, loc.fY, paint);
reed@google.com4b5894c2012-05-02 18:03:32 +0000189 }
190
191 void drawPredicates(SkCanvas* canvas, const SkPoint pts[]) {
192 SkRegion rgn;
193 build_base_rgn(&rgn);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000194
reed@google.com4b5894c2012-05-02 18:03:32 +0000195 drawstr(canvas, "Intersects", pts[0], rgn.intersects(fRect));
196 drawstr(canvas, "Contains", pts[1], rgn.contains(fRect));
197 }
198
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000199 void drawOrig(SkCanvas* canvas, bool bg) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200 SkRect r;
201 SkPaint paint;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000202
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203 paint.setStyle(SkPaint::kStroke_Style);
204 if (bg)
205 paint.setColor(0xFFBBBBBB);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000206
reed@google.com4b5894c2012-05-02 18:03:32 +0000207 SkRegion rgn;
208 build_base_rgn(&rgn);
209 paint_rgn(canvas, rgn, paint);
210
reed@android.com8a1c16f2008-12-17 15:59:43 +0000211 r.set(fRect);
212 canvas->drawRect(r, paint);
213 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000214
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000215 void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 SkRegion rgn;
217
218 this->build_rgn(&rgn, op);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000219
reed@android.com8a1c16f2008-12-17 15:59:43 +0000220 {
221 SkRegion tmp, tmp2(rgn);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000222
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223 tmp = tmp2;
224 tmp.translate(5, -3);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000225
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226 {
227 char buffer[1000];
halcanary96fcdcc2015-08-27 07:41:13 -0700228 SkDEBUGCODE(size_t size = ) tmp.writeToMemory(nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229 SkASSERT(size <= sizeof(buffer));
humper@google.com0e515772013-01-07 19:54:40 +0000230 SkDEBUGCODE(size_t size2 = ) tmp.writeToMemory(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231 SkASSERT(size == size2);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000232
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 SkRegion tmp3;
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000234 SkDEBUGCODE(size2 = ) tmp3.readFromMemory(buffer, 1000);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000235 SkASSERT(size == size2);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000236
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237 SkASSERT(tmp3 == tmp);
238 }
239
240 rgn.translate(20, 30, &tmp);
241 SkASSERT(rgn.isEmpty() || tmp != rgn);
242 tmp.translate(-20, -30);
243 SkASSERT(tmp == rgn);
244 }
245
246 this->drawOrig(canvas, true);
247
248 SkPaint paint;
249 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
250 paint_rgn(canvas, rgn, paint);
251
252 paint.setStyle(SkPaint::kStroke_Style);
253 paint.setColor(color);
254 paint_rgn(canvas, rgn, paint);
255 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000256
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000257 void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000258 SkRegion rgn;
259 SkPath path;
260
261 this->build_rgn(&rgn, op);
262 rgn.getBoundaryPath(&path);
263
264 this->drawOrig(canvas, true);
265
266 SkPaint paint;
267
268 paint.setStyle(SkPaint::kFill_Style);
269 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
270 canvas->drawPath(path, paint);
271 paint.setColor(color);
272 paint.setStyle(SkPaint::kStroke_Style);
273 canvas->drawPath(path, paint);
274 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000275
mtklein36352bf2015-03-25 18:17:31 -0700276 void onDrawContent(SkCanvas* canvas) override {
caryclark@google.com02939ce2012-06-06 12:09:51 +0000277 if (false) { // avoid bit rot, suppress warning
278 test_strokerect(canvas);
279 return;
280 }
281 if (false) { // avoid bit rot, suppress warning
282 test_text(canvas);
283 return;
284 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000285
reed@google.com4b5894c2012-05-02 18:03:32 +0000286 const SkPoint origins[] = {
287 { 30*SK_Scalar1, 50*SK_Scalar1 },
288 { 150*SK_Scalar1, 50*SK_Scalar1 },
289 };
290 this->drawPredicates(canvas, origins);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000291
292 static const struct {
293 SkColor fColor;
294 const char* fName;
295 SkRegion::Op fOp;
296 } gOps[] = {
297 { SK_ColorBLACK, "Difference", SkRegion::kDifference_Op },
298 { SK_ColorRED, "Intersect", SkRegion::kIntersect_Op },
299 { 0xFF008800, "Union", SkRegion::kUnion_Op },
300 { SK_ColorBLUE, "XOR", SkRegion::kXOR_Op }
301 };
302
303 SkPaint textPaint;
304 textPaint.setAntiAlias(true);
305 textPaint.setTextSize(SK_Scalar1*24);
306
307 this->drawOrig(canvas, false);
308 canvas->save();
309 canvas->translate(SkIntToScalar(200), 0);
310 this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK);
311 canvas->restore();
rmistry@google.comae933ce2012-08-23 18:19:56 +0000312
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313 canvas->translate(0, SkIntToScalar(200));
314
senorblanco@chromium.org64cc5792011-05-19 19:58:58 +0000315 for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); op++) {
Cary Clark2a475ea2017-04-28 15:35:12 -0400316 canvas->drawString(gOps[op].fName, SkIntToScalar(75), SkIntToScalar(50), textPaint);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000317
318 this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
319
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000320 canvas->save();
321 canvas->translate(0, SkIntToScalar(200));
322 this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
323 canvas->restore();
rmistry@google.comae933ce2012-08-23 18:19:56 +0000324
reed@android.com8a1c16f2008-12-17 15:59:43 +0000325 canvas->translate(SkIntToScalar(200), 0);
326 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000327 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000328
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400329 virtual Sample::Click* onFindClickHandler(SkScalar x, SkScalar y,
mtklein36352bf2015-03-25 18:17:31 -0700330 unsigned modi) override {
reed@google.come1ca7052013-12-17 19:22:07 +0000331 return fRect.contains(SkScalarRoundToInt(x),
halcanary96fcdcc2015-08-27 07:41:13 -0700332 SkScalarRoundToInt(y)) ? new Click(this) : nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000333 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000334
mtklein36352bf2015-03-25 18:17:31 -0700335 bool onClick(Click* click) override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000336 fRect.offset(click->fICurr.fX - click->fIPrev.fX,
337 click->fICurr.fY - click->fIPrev.fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338 return true;
339 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000340
reed@android.com8a1c16f2008-12-17 15:59:43 +0000341private:
342 SkIRect fBase, fRect;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000343
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400344 typedef Sample INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345};
346
347//////////////////////////////////////////////////////////////////////////////
348
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400349DEF_SAMPLE( return new RegionView(); )