blob: 409222e73031eb13ed7172809458ae8b48e7de20 [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"
Mike Reed91919132019-01-02 12:21:01 -050011#include "SkFont.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000012#include "SkGradientShader.h"
13#include "SkPath.h"
14#include "SkRegion.h"
15#include "SkShader.h"
Hal Canaryea60b952018-08-21 11:45:46 -040016#include "SkUTF.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,
Mike Reed91919132019-01-02 12:21:01 -050057 const SkFont& font, const SkPaint& paint) {
reed@google.com4b5894c2012-05-02 18:03:32 +000058 // Need a bounds for the text
59 SkRect bounds;
Mike Reedb5784ac2018-11-12 09:35:15 -050060 SkFontMetrics fm;
rmistry@google.comae933ce2012-08-23 18:19:56 +000061
Mike Reed91919132019-01-02 12:21:01 -050062 font.getMetrics(&fm);
63 bounds.set(x, y + fm.fTop, x + font.measureText(text, len, kUTF8_SkTextEncoding), y + fm.fBottom);
reed@google.com4b5894c2012-05-02 18:03:32 +000064
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);
Mike Reed91919132019-01-02 12:21:01 -050070 canvas->drawSimpleText(text, len, kUTF8_SkTextEncoding, x, y, font, paint);
reed@google.com4b5894c2012-05-02 18:03:32 +000071
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);
Mike Reed91919132019-01-02 12:21:01 -050093
94 SkFont font;
95 font.setSize(20);
rmistry@google.comae933ce2012-08-23 18:19:56 +000096
reed@google.com4b5894c2012-05-02 18:03:32 +000097 const char* str = "Hamburgefons";
98 size_t len = strlen(str);
99 SkScalar x = 20;
100 SkScalar y = 20;
101
Mike Reed91919132019-01-02 12:21:01 -0500102 canvas->drawSimpleText(str, len, kUTF8_SkTextEncoding, x, y, font, paint);
reed@google.com4b5894c2012-05-02 18:03:32 +0000103
104 y += 20;
105
Mike Reed91919132019-01-02 12:21:01 -0500106 const SkPoint pts[] = { { x, y }, { x + font.measureText(str, len, kUTF8_SkTextEncoding), y } };
reed@google.com4b5894c2012-05-02 18:03:32 +0000107 const SkColor colors[] = { SK_ColorBLACK, SK_ColorBLACK, 0 };
108 const SkScalar pos[] = { 0, 0.9f, 1 };
reed8a21c9f2016-03-08 18:50:00 -0800109 paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos,
reed@google.com4b5894c2012-05-02 18:03:32 +0000110 SK_ARRAY_COUNT(colors),
reed8a21c9f2016-03-08 18:50:00 -0800111 SkShader::kClamp_TileMode));
Mike Reed91919132019-01-02 12:21:01 -0500112 canvas->drawSimpleText(str, len, kUTF8_SkTextEncoding, x, y, font, paint);
reed@google.com4b5894c2012-05-02 18:03:32 +0000113
114 y += 20;
halcanary96fcdcc2015-08-27 07:41:13 -0700115 paint.setShader(nullptr);
Mike Reed91919132019-01-02 12:21:01 -0500116 drawFadingText(canvas, str, len, x, y, font, paint);
reed@google.com4b5894c2012-05-02 18:03:32 +0000117}
118
reed@android.comf76bacf2009-05-13 14:00:33 +0000119static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
120 dst->fLeft = (int)::roundf(src.fLeft * scale);
121 dst->fTop = (int)::roundf(src.fTop * scale);
122 dst->fRight = (int)::roundf(src.fRight * scale);
123 dst->fBottom = (int)::roundf(src.fBottom * scale);
124}
125
126static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
127 SkRegion tmp;
128 SkRegion::Iterator iter(src);
129
130 for (; !iter.done(); iter.next()) {
131 SkIRect r;
132 scale_rect(&r, iter.rect(), scale);
133 tmp.op(r, SkRegion::kUnion_Op);
134 }
135 dst->swap(tmp);
136}
137
138static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn,
139 const SkPaint& paint) {
140 SkRegion scaled;
141 scale_rgn(&scaled, rgn, 0.5f);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000142
reed@android.comf76bacf2009-05-13 14:00:33 +0000143 SkRegion::Iterator iter(rgn);
144
reed@android.com8a1c16f2008-12-17 15:59:43 +0000145 for (; !iter.done(); iter.next())
146 {
147 SkRect r;
148 r.set(iter.rect());
149 canvas->drawRect(r, paint);
150 }
151}
152
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400153class RegionView : public Sample {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154public:
rmistry@google.comae933ce2012-08-23 18:19:56 +0000155 RegionView() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000156 fBase.set(100, 100, 150, 150);
157 fRect = fBase;
158 fRect.inset(5, 5);
159 fRect.offset(25, 25);
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000160 this->setBGColor(0xFFDDDDDD);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161 }
162
reed@google.com4b5894c2012-05-02 18:03:32 +0000163 void build_base_rgn(SkRegion* rgn) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000164 rgn->setRect(fBase);
165 SkIRect r = fBase;
166 r.offset(75, 20);
167 rgn->op(r, SkRegion::kUnion_Op);
reed@google.com4b5894c2012-05-02 18:03:32 +0000168 }
169
170 void build_rgn(SkRegion* rgn, SkRegion::Op op) {
171 build_base_rgn(rgn);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172 rgn->op(fRect, op);
173 }
174
175
176protected:
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400177 bool onQuery(Sample::Event* evt) override {
178 if (Sample::TitleQ(*evt)) {
179 Sample::TitleR(evt, "Regions");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180 return true;
181 }
182 return this->INHERITED::onQuery(evt);
183 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000184
reed@google.com4b5894c2012-05-02 18:03:32 +0000185 static void drawstr(SkCanvas* canvas, const char text[], const SkPoint& loc,
186 bool hilite) {
187 SkPaint paint;
188 paint.setAntiAlias(true);
189 paint.setTextSize(SkIntToScalar(20));
190 paint.setColor(hilite ? SK_ColorRED : 0x40FF0000);
Cary Clark2a475ea2017-04-28 15:35:12 -0400191 canvas->drawString(text, loc.fX, loc.fY, paint);
reed@google.com4b5894c2012-05-02 18:03:32 +0000192 }
193
194 void drawPredicates(SkCanvas* canvas, const SkPoint pts[]) {
195 SkRegion rgn;
196 build_base_rgn(&rgn);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000197
reed@google.com4b5894c2012-05-02 18:03:32 +0000198 drawstr(canvas, "Intersects", pts[0], rgn.intersects(fRect));
199 drawstr(canvas, "Contains", pts[1], rgn.contains(fRect));
200 }
201
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000202 void drawOrig(SkCanvas* canvas, bool bg) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203 SkRect r;
204 SkPaint paint;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000205
reed@android.com8a1c16f2008-12-17 15:59:43 +0000206 paint.setStyle(SkPaint::kStroke_Style);
207 if (bg)
208 paint.setColor(0xFFBBBBBB);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000209
reed@google.com4b5894c2012-05-02 18:03:32 +0000210 SkRegion rgn;
211 build_base_rgn(&rgn);
212 paint_rgn(canvas, rgn, paint);
213
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214 r.set(fRect);
215 canvas->drawRect(r, paint);
216 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000217
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000218 void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 SkRegion rgn;
220
221 this->build_rgn(&rgn, op);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000222
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223 {
224 SkRegion tmp, tmp2(rgn);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000225
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226 tmp = tmp2;
227 tmp.translate(5, -3);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000228
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229 {
230 char buffer[1000];
halcanary96fcdcc2015-08-27 07:41:13 -0700231 SkDEBUGCODE(size_t size = ) tmp.writeToMemory(nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232 SkASSERT(size <= sizeof(buffer));
humper@google.com0e515772013-01-07 19:54:40 +0000233 SkDEBUGCODE(size_t size2 = ) tmp.writeToMemory(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 SkASSERT(size == size2);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000235
reed@android.com8a1c16f2008-12-17 15:59:43 +0000236 SkRegion tmp3;
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000237 SkDEBUGCODE(size2 = ) tmp3.readFromMemory(buffer, 1000);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238 SkASSERT(size == size2);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000239
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240 SkASSERT(tmp3 == tmp);
241 }
242
243 rgn.translate(20, 30, &tmp);
244 SkASSERT(rgn.isEmpty() || tmp != rgn);
245 tmp.translate(-20, -30);
246 SkASSERT(tmp == rgn);
247 }
248
249 this->drawOrig(canvas, true);
250
251 SkPaint paint;
252 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
253 paint_rgn(canvas, rgn, paint);
254
255 paint.setStyle(SkPaint::kStroke_Style);
256 paint.setColor(color);
257 paint_rgn(canvas, rgn, paint);
258 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000259
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000260 void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000261 SkRegion rgn;
262 SkPath path;
263
264 this->build_rgn(&rgn, op);
265 rgn.getBoundaryPath(&path);
266
267 this->drawOrig(canvas, true);
268
269 SkPaint paint;
270
271 paint.setStyle(SkPaint::kFill_Style);
272 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
273 canvas->drawPath(path, paint);
274 paint.setColor(color);
275 paint.setStyle(SkPaint::kStroke_Style);
276 canvas->drawPath(path, paint);
277 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000278
mtklein36352bf2015-03-25 18:17:31 -0700279 void onDrawContent(SkCanvas* canvas) override {
caryclark@google.com02939ce2012-06-06 12:09:51 +0000280 if (false) { // avoid bit rot, suppress warning
281 test_strokerect(canvas);
282 return;
283 }
284 if (false) { // avoid bit rot, suppress warning
285 test_text(canvas);
286 return;
287 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000288
reed@google.com4b5894c2012-05-02 18:03:32 +0000289 const SkPoint origins[] = {
290 { 30*SK_Scalar1, 50*SK_Scalar1 },
291 { 150*SK_Scalar1, 50*SK_Scalar1 },
292 };
293 this->drawPredicates(canvas, origins);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294
295 static const struct {
296 SkColor fColor;
297 const char* fName;
298 SkRegion::Op fOp;
299 } gOps[] = {
300 { SK_ColorBLACK, "Difference", SkRegion::kDifference_Op },
301 { SK_ColorRED, "Intersect", SkRegion::kIntersect_Op },
302 { 0xFF008800, "Union", SkRegion::kUnion_Op },
303 { SK_ColorBLUE, "XOR", SkRegion::kXOR_Op }
304 };
305
306 SkPaint textPaint;
307 textPaint.setAntiAlias(true);
308 textPaint.setTextSize(SK_Scalar1*24);
309
310 this->drawOrig(canvas, false);
311 canvas->save();
312 canvas->translate(SkIntToScalar(200), 0);
313 this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK);
314 canvas->restore();
rmistry@google.comae933ce2012-08-23 18:19:56 +0000315
reed@android.com8a1c16f2008-12-17 15:59:43 +0000316 canvas->translate(0, SkIntToScalar(200));
317
senorblanco@chromium.org64cc5792011-05-19 19:58:58 +0000318 for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); op++) {
Cary Clark2a475ea2017-04-28 15:35:12 -0400319 canvas->drawString(gOps[op].fName, SkIntToScalar(75), SkIntToScalar(50), textPaint);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000320
321 this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
322
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000323 canvas->save();
324 canvas->translate(0, SkIntToScalar(200));
325 this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
326 canvas->restore();
rmistry@google.comae933ce2012-08-23 18:19:56 +0000327
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328 canvas->translate(SkIntToScalar(200), 0);
329 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000330 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000331
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400332 virtual Sample::Click* onFindClickHandler(SkScalar x, SkScalar y,
mtklein36352bf2015-03-25 18:17:31 -0700333 unsigned modi) override {
reed@google.come1ca7052013-12-17 19:22:07 +0000334 return fRect.contains(SkScalarRoundToInt(x),
halcanary96fcdcc2015-08-27 07:41:13 -0700335 SkScalarRoundToInt(y)) ? new Click(this) : nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000336 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000337
mtklein36352bf2015-03-25 18:17:31 -0700338 bool onClick(Click* click) override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000339 fRect.offset(click->fICurr.fX - click->fIPrev.fX,
340 click->fICurr.fY - click->fIPrev.fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000341 return true;
342 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000343
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344private:
345 SkIRect fBase, fRect;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000346
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400347 typedef Sample INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000348};
349
350//////////////////////////////////////////////////////////////////////////////
351
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400352DEF_SAMPLE( return new RegionView(); )