blob: 30ed3dfe50004162d54e27169db441ad4fb60251 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkBitmap.h"
9#include "include/core/SkCanvas.h"
10#include "include/core/SkFont.h"
11#include "include/core/SkFontMetrics.h"
12#include "include/core/SkPath.h"
13#include "include/core/SkRegion.h"
14#include "include/core/SkShader.h"
15#include "include/effects/SkGradientShader.h"
16#include "samplecode/Sample.h"
17#include "src/utils/SkUTF.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000018
bungemanb7069e92015-07-21 14:14:30 -070019#include <math.h>
20
reed@google.com4b5894c2012-05-02 18:03:32 +000021static void test_strokerect(SkCanvas* canvas) {
22 int width = 100;
23 int height = 100;
24
25 SkBitmap bitmap;
commit-bot@chromium.orga8c18312014-02-17 02:55:57 +000026 bitmap.allocPixels(SkImageInfo::MakeA8(width*2, height*2));
junov@google.comdbfac8a2012-12-06 21:47:40 +000027 bitmap.eraseColor(SK_ColorTRANSPARENT);
reed@google.com4b5894c2012-05-02 18:03:32 +000028
29 SkScalar dx = 20;
30 SkScalar dy = 20;
rmistry@google.comae933ce2012-08-23 18:19:56 +000031
reed@google.com4b5894c2012-05-02 18:03:32 +000032 SkPath path;
Mike Reed4241f5e2019-09-14 19:13:23 +000033 path.addRect(0.0f, 0.0f,
34 SkIntToScalar(width), SkIntToScalar(height),
Mike Reed30bc5272019-11-22 18:34:02 +000035 SkPathDirection::kCW);
robertphillips@google.com4debcac2012-05-14 16:33:36 +000036 SkRect r = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
rmistry@google.comae933ce2012-08-23 18:19:56 +000037
reed@google.com4b5894c2012-05-02 18:03:32 +000038 SkCanvas c(bitmap);
39 c.translate(dx, dy);
40
41 SkPaint paint;
42 paint.setStyle(SkPaint::kStroke_Style);
43 paint.setStrokeWidth(1);
44
45 // use the rect
junov@google.comdbfac8a2012-12-06 21:47:40 +000046 c.clear(SK_ColorTRANSPARENT);
reed@google.com4b5894c2012-05-02 18:03:32 +000047 c.drawRect(r, paint);
halcanary96fcdcc2015-08-27 07:41:13 -070048 canvas->drawBitmap(bitmap, 0, 0, nullptr);
reed@google.com4b5894c2012-05-02 18:03:32 +000049
50 // use the path
junov@google.comdbfac8a2012-12-06 21:47:40 +000051 c.clear(SK_ColorTRANSPARENT);
reed@google.com4b5894c2012-05-02 18:03:32 +000052 c.drawPath(path, paint);
halcanary96fcdcc2015-08-27 07:41:13 -070053 canvas->drawBitmap(bitmap, SkIntToScalar(2*width), 0, nullptr);
reed@google.com4b5894c2012-05-02 18:03:32 +000054}
55
56static void drawFadingText(SkCanvas* canvas,
57 const char* text, size_t len, SkScalar x, SkScalar y,
Mike Reed91919132019-01-02 12:21:01 -050058 const SkFont& font, const SkPaint& paint) {
reed@google.com4b5894c2012-05-02 18:03:32 +000059 // Need a bounds for the text
60 SkRect bounds;
Mike Reedb5784ac2018-11-12 09:35:15 -050061 SkFontMetrics fm;
rmistry@google.comae933ce2012-08-23 18:19:56 +000062
Mike Reed91919132019-01-02 12:21:01 -050063 font.getMetrics(&fm);
Mike Reed92b33352019-08-24 19:39:13 -040064 bounds.setLTRB(x, y + fm.fTop,
65 x + font.measureText(text, len, SkTextEncoding::kUTF8), y + fm.fBottom);
reed@google.com4b5894c2012-05-02 18:03:32 +000066
67 // may need to outset bounds a little, to account for hinting and/or
68 // antialiasing
69 bounds.inset(-SkIntToScalar(2), -SkIntToScalar(2));
70
halcanary96fcdcc2015-08-27 07:41:13 -070071 canvas->saveLayer(&bounds, nullptr);
Ben Wagner51e15a62019-05-07 15:38:46 -040072 canvas->drawSimpleText(text, len, SkTextEncoding::kUTF8, x, y, font, paint);
reed@google.com4b5894c2012-05-02 18:03:32 +000073
74 const SkPoint pts[] = {
75 { bounds.fLeft, y },
76 { bounds.fRight, y }
77 };
78 const SkColor colors[] = { SK_ColorBLACK, SK_ColorBLACK, 0 };
79
80 // pos[1] value is where we start to fade, relative to the width
81 // of our pts[] array.
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000082 const SkScalar pos[] = { 0, 0.9f, SK_Scalar1 };
reed@google.com4b5894c2012-05-02 18:03:32 +000083
reed@google.com4b5894c2012-05-02 18:03:32 +000084 SkPaint p;
Mike Reedfae8fce2019-04-03 10:27:45 -040085 p.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 3, SkTileMode::kClamp));
reed374772b2016-10-05 17:33:02 -070086 p.setBlendMode(SkBlendMode::kDstIn);
reed@google.com4b5894c2012-05-02 18:03:32 +000087 canvas->drawRect(bounds, p);
88
89 canvas->restore();
90}
91
92static void test_text(SkCanvas* canvas) {
93 SkPaint paint;
94 paint.setAntiAlias(true);
Mike Reed91919132019-01-02 12:21:01 -050095
96 SkFont font;
97 font.setSize(20);
rmistry@google.comae933ce2012-08-23 18:19:56 +000098
reed@google.com4b5894c2012-05-02 18:03:32 +000099 const char* str = "Hamburgefons";
100 size_t len = strlen(str);
101 SkScalar x = 20;
102 SkScalar y = 20;
103
Ben Wagner51e15a62019-05-07 15:38:46 -0400104 canvas->drawSimpleText(str, len, SkTextEncoding::kUTF8, x, y, font, paint);
reed@google.com4b5894c2012-05-02 18:03:32 +0000105
106 y += 20;
107
Ben Wagner51e15a62019-05-07 15:38:46 -0400108 const SkPoint pts[] = { { x , y },
109 { x + font.measureText(str, len, SkTextEncoding::kUTF8), y } };
reed@google.com4b5894c2012-05-02 18:03:32 +0000110 const SkColor colors[] = { SK_ColorBLACK, SK_ColorBLACK, 0 };
111 const SkScalar pos[] = { 0, 0.9f, 1 };
reed8a21c9f2016-03-08 18:50:00 -0800112 paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos,
reed@google.com4b5894c2012-05-02 18:03:32 +0000113 SK_ARRAY_COUNT(colors),
Mike Reedfae8fce2019-04-03 10:27:45 -0400114 SkTileMode::kClamp));
Ben Wagner51e15a62019-05-07 15:38:46 -0400115 canvas->drawSimpleText(str, len, SkTextEncoding::kUTF8, x, y, font, paint);
reed@google.com4b5894c2012-05-02 18:03:32 +0000116
117 y += 20;
halcanary96fcdcc2015-08-27 07:41:13 -0700118 paint.setShader(nullptr);
Mike Reed91919132019-01-02 12:21:01 -0500119 drawFadingText(canvas, str, len, x, y, font, paint);
reed@google.com4b5894c2012-05-02 18:03:32 +0000120}
121
reed@android.comf76bacf2009-05-13 14:00:33 +0000122static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
123 dst->fLeft = (int)::roundf(src.fLeft * scale);
124 dst->fTop = (int)::roundf(src.fTop * scale);
125 dst->fRight = (int)::roundf(src.fRight * scale);
126 dst->fBottom = (int)::roundf(src.fBottom * scale);
127}
128
129static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
130 SkRegion tmp;
131 SkRegion::Iterator iter(src);
132
133 for (; !iter.done(); iter.next()) {
134 SkIRect r;
135 scale_rect(&r, iter.rect(), scale);
136 tmp.op(r, SkRegion::kUnion_Op);
137 }
138 dst->swap(tmp);
139}
140
141static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn,
142 const SkPaint& paint) {
143 SkRegion scaled;
144 scale_rgn(&scaled, rgn, 0.5f);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000145
reed@android.comf76bacf2009-05-13 14:00:33 +0000146 SkRegion::Iterator iter(rgn);
147
reed@android.com8a1c16f2008-12-17 15:59:43 +0000148 for (; !iter.done(); iter.next())
149 {
150 SkRect r;
151 r.set(iter.rect());
152 canvas->drawRect(r, paint);
153 }
154}
155
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400156class RegionView : public Sample {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157public:
rmistry@google.comae933ce2012-08-23 18:19:56 +0000158 RegionView() {
Mike Reed92b33352019-08-24 19:39:13 -0400159 fBase.setLTRB(100, 100, 150, 150);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160 fRect = fBase;
161 fRect.inset(5, 5);
162 fRect.offset(25, 25);
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000163 this->setBGColor(0xFFDDDDDD);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000164 }
165
reed@google.com4b5894c2012-05-02 18:03:32 +0000166 void build_base_rgn(SkRegion* rgn) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167 rgn->setRect(fBase);
168 SkIRect r = fBase;
169 r.offset(75, 20);
170 rgn->op(r, SkRegion::kUnion_Op);
reed@google.com4b5894c2012-05-02 18:03:32 +0000171 }
172
173 void build_rgn(SkRegion* rgn, SkRegion::Op op) {
174 build_base_rgn(rgn);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175 rgn->op(fRect, op);
176 }
177
178
179protected:
Hal Canary8a027312019-07-03 10:55:44 -0400180 SkString name() override { return SkString("Regions"); }
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;
reed@google.com4b5894c2012-05-02 18:03:32 +0000185 paint.setColor(hilite ? SK_ColorRED : 0x40FF0000);
Mike Reed89126e42019-01-03 12:59:14 -0500186 SkFont font;
187 font.setSize(SkIntToScalar(20));
Ben Wagner51e15a62019-05-07 15:38:46 -0400188 canvas->drawSimpleText(text, strlen(text), SkTextEncoding::kUTF8, loc.fX, loc.fY, font, 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 {
John Stiles31954bf2020-08-07 17:35:54 -0400221 SkRegion tmp = rgn;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 tmp.translate(5, -3);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000223
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224 {
225 char buffer[1000];
halcanary96fcdcc2015-08-27 07:41:13 -0700226 SkDEBUGCODE(size_t size = ) tmp.writeToMemory(nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227 SkASSERT(size <= sizeof(buffer));
humper@google.com0e515772013-01-07 19:54:40 +0000228 SkDEBUGCODE(size_t size2 = ) tmp.writeToMemory(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229 SkASSERT(size == size2);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000230
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231 SkRegion tmp3;
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000232 SkDEBUGCODE(size2 = ) tmp3.readFromMemory(buffer, 1000);
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 SkASSERT(tmp3 == tmp);
236 }
237
238 rgn.translate(20, 30, &tmp);
239 SkASSERT(rgn.isEmpty() || tmp != rgn);
240 tmp.translate(-20, -30);
241 SkASSERT(tmp == rgn);
242 }
243
244 this->drawOrig(canvas, true);
245
246 SkPaint paint;
247 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
248 paint_rgn(canvas, rgn, paint);
249
250 paint.setStyle(SkPaint::kStroke_Style);
251 paint.setColor(color);
252 paint_rgn(canvas, rgn, paint);
253 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000254
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000255 void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000256 SkRegion rgn;
257 SkPath path;
258
259 this->build_rgn(&rgn, op);
260 rgn.getBoundaryPath(&path);
261
262 this->drawOrig(canvas, true);
263
264 SkPaint paint;
265
266 paint.setStyle(SkPaint::kFill_Style);
267 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
268 canvas->drawPath(path, paint);
269 paint.setColor(color);
270 paint.setStyle(SkPaint::kStroke_Style);
271 canvas->drawPath(path, paint);
272 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000273
mtklein36352bf2015-03-25 18:17:31 -0700274 void onDrawContent(SkCanvas* canvas) override {
caryclark@google.com02939ce2012-06-06 12:09:51 +0000275 if (false) { // avoid bit rot, suppress warning
276 test_strokerect(canvas);
277 return;
278 }
279 if (false) { // avoid bit rot, suppress warning
280 test_text(canvas);
281 return;
282 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000283
reed@google.com4b5894c2012-05-02 18:03:32 +0000284 const SkPoint origins[] = {
285 { 30*SK_Scalar1, 50*SK_Scalar1 },
286 { 150*SK_Scalar1, 50*SK_Scalar1 },
287 };
288 this->drawPredicates(canvas, origins);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289
290 static const struct {
291 SkColor fColor;
292 const char* fName;
293 SkRegion::Op fOp;
294 } gOps[] = {
295 { SK_ColorBLACK, "Difference", SkRegion::kDifference_Op },
296 { SK_ColorRED, "Intersect", SkRegion::kIntersect_Op },
297 { 0xFF008800, "Union", SkRegion::kUnion_Op },
298 { SK_ColorBLUE, "XOR", SkRegion::kXOR_Op }
299 };
300
Mike Reed89126e42019-01-03 12:59:14 -0500301 SkFont font;
302 font.setSize(SK_Scalar1*24);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000303
304 this->drawOrig(canvas, false);
305 canvas->save();
306 canvas->translate(SkIntToScalar(200), 0);
307 this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK);
308 canvas->restore();
rmistry@google.comae933ce2012-08-23 18:19:56 +0000309
reed@android.com8a1c16f2008-12-17 15:59:43 +0000310 canvas->translate(0, SkIntToScalar(200));
311
senorblanco@chromium.org64cc5792011-05-19 19:58:58 +0000312 for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); op++) {
Ben Wagner51e15a62019-05-07 15:38:46 -0400313 canvas->drawSimpleText(gOps[op].fName, strlen(gOps[op].fName), SkTextEncoding::kUTF8,
Mike Reed89126e42019-01-03 12:59:14 -0500314 SkIntToScalar(75), SkIntToScalar(50), font, SkPaint());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000315
316 this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
317
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000318 canvas->save();
319 canvas->translate(0, SkIntToScalar(200));
320 this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
321 canvas->restore();
rmistry@google.comae933ce2012-08-23 18:19:56 +0000322
reed@android.com8a1c16f2008-12-17 15:59:43 +0000323 canvas->translate(SkIntToScalar(200), 0);
324 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000325 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000326
John Stiles1cf2c8d2020-08-13 22:58:04 -0400327 Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
reed@google.come1ca7052013-12-17 19:22:07 +0000328 return fRect.contains(SkScalarRoundToInt(x),
Hal Canaryfcf63592019-07-12 11:32:43 -0400329 SkScalarRoundToInt(y)) ? new Click() : nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000330 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000331
mtklein36352bf2015-03-25 18:17:31 -0700332 bool onClick(Click* click) override {
Hal Canaryfcf63592019-07-12 11:32:43 -0400333 fRect.offset(click->fCurr.fX - click->fPrev.fX,
334 click->fCurr.fY - click->fPrev.fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335 return true;
336 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000337
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338private:
339 SkIRect fBase, fRect;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000340
John Stiles7571f9e2020-09-02 22:42:33 -0400341 using INHERITED = Sample;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342};
343
344//////////////////////////////////////////////////////////////////////////////
345
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400346DEF_SAMPLE( return new RegionView(); )