blob: c5eaf009fd6f1608ee16336a7a639d1e0d4ddd42 [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"
Mike Reed9cd2a5c2019-01-22 15:17:59 -050012#include "SkFontMetrics.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkGradientShader.h"
14#include "SkPath.h"
15#include "SkRegion.h"
16#include "SkShader.h"
Hal Canaryea60b952018-08-21 11:45:46 -040017#include "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;
rmistry@google.comae933ce2012-08-23 18:19:56 +000033 path.addRect(0.0f, 0.0f,
34 SkIntToScalar(width), SkIntToScalar(height),
robertphillips@google.com4debcac2012-05-14 16:33:36 +000035 SkPath::kCW_Direction);
36 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);
64 bounds.set(x, y + fm.fTop, x + font.measureText(text, len, kUTF8_SkTextEncoding), y + fm.fBottom);
reed@google.com4b5894c2012-05-02 18:03:32 +000065
66 // may need to outset bounds a little, to account for hinting and/or
67 // antialiasing
68 bounds.inset(-SkIntToScalar(2), -SkIntToScalar(2));
69
halcanary96fcdcc2015-08-27 07:41:13 -070070 canvas->saveLayer(&bounds, nullptr);
Mike Reed91919132019-01-02 12:21:01 -050071 canvas->drawSimpleText(text, len, kUTF8_SkTextEncoding, x, y, font, paint);
reed@google.com4b5894c2012-05-02 18:03:32 +000072
73 const SkPoint pts[] = {
74 { bounds.fLeft, y },
75 { bounds.fRight, y }
76 };
77 const SkColor colors[] = { SK_ColorBLACK, SK_ColorBLACK, 0 };
78
79 // pos[1] value is where we start to fade, relative to the width
80 // of our pts[] array.
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000081 const SkScalar pos[] = { 0, 0.9f, SK_Scalar1 };
reed@google.com4b5894c2012-05-02 18:03:32 +000082
reed@google.com4b5894c2012-05-02 18:03:32 +000083 SkPaint p;
reed8a21c9f2016-03-08 18:50:00 -080084 p.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 3, SkShader::kClamp_TileMode));
reed374772b2016-10-05 17:33:02 -070085 p.setBlendMode(SkBlendMode::kDstIn);
reed@google.com4b5894c2012-05-02 18:03:32 +000086 canvas->drawRect(bounds, p);
87
88 canvas->restore();
89}
90
91static void test_text(SkCanvas* canvas) {
92 SkPaint paint;
93 paint.setAntiAlias(true);
Mike Reed91919132019-01-02 12:21:01 -050094
95 SkFont font;
96 font.setSize(20);
rmistry@google.comae933ce2012-08-23 18:19:56 +000097
reed@google.com4b5894c2012-05-02 18:03:32 +000098 const char* str = "Hamburgefons";
99 size_t len = strlen(str);
100 SkScalar x = 20;
101 SkScalar y = 20;
102
Mike Reed91919132019-01-02 12:21:01 -0500103 canvas->drawSimpleText(str, len, kUTF8_SkTextEncoding, x, y, font, paint);
reed@google.com4b5894c2012-05-02 18:03:32 +0000104
105 y += 20;
106
Mike Reed91919132019-01-02 12:21:01 -0500107 const SkPoint pts[] = { { x, y }, { x + font.measureText(str, len, kUTF8_SkTextEncoding), y } };
reed@google.com4b5894c2012-05-02 18:03:32 +0000108 const SkColor colors[] = { SK_ColorBLACK, SK_ColorBLACK, 0 };
109 const SkScalar pos[] = { 0, 0.9f, 1 };
reed8a21c9f2016-03-08 18:50:00 -0800110 paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos,
reed@google.com4b5894c2012-05-02 18:03:32 +0000111 SK_ARRAY_COUNT(colors),
reed8a21c9f2016-03-08 18:50:00 -0800112 SkShader::kClamp_TileMode));
Mike Reed91919132019-01-02 12:21:01 -0500113 canvas->drawSimpleText(str, len, kUTF8_SkTextEncoding, x, y, font, paint);
reed@google.com4b5894c2012-05-02 18:03:32 +0000114
115 y += 20;
halcanary96fcdcc2015-08-27 07:41:13 -0700116 paint.setShader(nullptr);
Mike Reed91919132019-01-02 12:21:01 -0500117 drawFadingText(canvas, str, len, x, y, font, paint);
reed@google.com4b5894c2012-05-02 18:03:32 +0000118}
119
reed@android.comf76bacf2009-05-13 14:00:33 +0000120static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
121 dst->fLeft = (int)::roundf(src.fLeft * scale);
122 dst->fTop = (int)::roundf(src.fTop * scale);
123 dst->fRight = (int)::roundf(src.fRight * scale);
124 dst->fBottom = (int)::roundf(src.fBottom * scale);
125}
126
127static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
128 SkRegion tmp;
129 SkRegion::Iterator iter(src);
130
131 for (; !iter.done(); iter.next()) {
132 SkIRect r;
133 scale_rect(&r, iter.rect(), scale);
134 tmp.op(r, SkRegion::kUnion_Op);
135 }
136 dst->swap(tmp);
137}
138
139static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn,
140 const SkPaint& paint) {
141 SkRegion scaled;
142 scale_rgn(&scaled, rgn, 0.5f);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000143
reed@android.comf76bacf2009-05-13 14:00:33 +0000144 SkRegion::Iterator iter(rgn);
145
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146 for (; !iter.done(); iter.next())
147 {
148 SkRect r;
149 r.set(iter.rect());
150 canvas->drawRect(r, paint);
151 }
152}
153
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400154class RegionView : public Sample {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000155public:
rmistry@google.comae933ce2012-08-23 18:19:56 +0000156 RegionView() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157 fBase.set(100, 100, 150, 150);
158 fRect = fBase;
159 fRect.inset(5, 5);
160 fRect.offset(25, 25);
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000161 this->setBGColor(0xFFDDDDDD);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000162 }
163
reed@google.com4b5894c2012-05-02 18:03:32 +0000164 void build_base_rgn(SkRegion* rgn) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165 rgn->setRect(fBase);
166 SkIRect r = fBase;
167 r.offset(75, 20);
168 rgn->op(r, SkRegion::kUnion_Op);
reed@google.com4b5894c2012-05-02 18:03:32 +0000169 }
170
171 void build_rgn(SkRegion* rgn, SkRegion::Op op) {
172 build_base_rgn(rgn);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173 rgn->op(fRect, op);
174 }
175
176
177protected:
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400178 bool onQuery(Sample::Event* evt) override {
179 if (Sample::TitleQ(*evt)) {
180 Sample::TitleR(evt, "Regions");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000181 return true;
182 }
183 return this->INHERITED::onQuery(evt);
184 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000185
reed@google.com4b5894c2012-05-02 18:03:32 +0000186 static void drawstr(SkCanvas* canvas, const char text[], const SkPoint& loc,
187 bool hilite) {
188 SkPaint paint;
reed@google.com4b5894c2012-05-02 18:03:32 +0000189 paint.setColor(hilite ? SK_ColorRED : 0x40FF0000);
Mike Reed89126e42019-01-03 12:59:14 -0500190 SkFont font;
191 font.setSize(SkIntToScalar(20));
192 canvas->drawSimpleText(text, strlen(text), kUTF8_SkTextEncoding, loc.fX, loc.fY, font, paint);
reed@google.com4b5894c2012-05-02 18:03:32 +0000193 }
194
195 void drawPredicates(SkCanvas* canvas, const SkPoint pts[]) {
196 SkRegion rgn;
197 build_base_rgn(&rgn);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000198
reed@google.com4b5894c2012-05-02 18:03:32 +0000199 drawstr(canvas, "Intersects", pts[0], rgn.intersects(fRect));
200 drawstr(canvas, "Contains", pts[1], rgn.contains(fRect));
201 }
202
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000203 void drawOrig(SkCanvas* canvas, bool bg) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204 SkRect r;
205 SkPaint paint;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000206
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207 paint.setStyle(SkPaint::kStroke_Style);
208 if (bg)
209 paint.setColor(0xFFBBBBBB);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000210
reed@google.com4b5894c2012-05-02 18:03:32 +0000211 SkRegion rgn;
212 build_base_rgn(&rgn);
213 paint_rgn(canvas, rgn, paint);
214
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215 r.set(fRect);
216 canvas->drawRect(r, paint);
217 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000218
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000219 void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000220 SkRegion rgn;
221
222 this->build_rgn(&rgn, op);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000223
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224 {
225 SkRegion tmp, tmp2(rgn);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000226
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227 tmp = tmp2;
228 tmp.translate(5, -3);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000229
reed@android.com8a1c16f2008-12-17 15:59:43 +0000230 {
231 char buffer[1000];
halcanary96fcdcc2015-08-27 07:41:13 -0700232 SkDEBUGCODE(size_t size = ) tmp.writeToMemory(nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 SkASSERT(size <= sizeof(buffer));
humper@google.com0e515772013-01-07 19:54:40 +0000234 SkDEBUGCODE(size_t size2 = ) tmp.writeToMemory(buffer);
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 SkRegion tmp3;
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000238 SkDEBUGCODE(size2 = ) tmp3.readFromMemory(buffer, 1000);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 SkASSERT(size == size2);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000240
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241 SkASSERT(tmp3 == tmp);
242 }
243
244 rgn.translate(20, 30, &tmp);
245 SkASSERT(rgn.isEmpty() || tmp != rgn);
246 tmp.translate(-20, -30);
247 SkASSERT(tmp == rgn);
248 }
249
250 this->drawOrig(canvas, true);
251
252 SkPaint paint;
253 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
254 paint_rgn(canvas, rgn, paint);
255
256 paint.setStyle(SkPaint::kStroke_Style);
257 paint.setColor(color);
258 paint_rgn(canvas, rgn, paint);
259 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000260
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000261 void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000262 SkRegion rgn;
263 SkPath path;
264
265 this->build_rgn(&rgn, op);
266 rgn.getBoundaryPath(&path);
267
268 this->drawOrig(canvas, true);
269
270 SkPaint paint;
271
272 paint.setStyle(SkPaint::kFill_Style);
273 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
274 canvas->drawPath(path, paint);
275 paint.setColor(color);
276 paint.setStyle(SkPaint::kStroke_Style);
277 canvas->drawPath(path, paint);
278 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000279
mtklein36352bf2015-03-25 18:17:31 -0700280 void onDrawContent(SkCanvas* canvas) override {
caryclark@google.com02939ce2012-06-06 12:09:51 +0000281 if (false) { // avoid bit rot, suppress warning
282 test_strokerect(canvas);
283 return;
284 }
285 if (false) { // avoid bit rot, suppress warning
286 test_text(canvas);
287 return;
288 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000289
reed@google.com4b5894c2012-05-02 18:03:32 +0000290 const SkPoint origins[] = {
291 { 30*SK_Scalar1, 50*SK_Scalar1 },
292 { 150*SK_Scalar1, 50*SK_Scalar1 },
293 };
294 this->drawPredicates(canvas, origins);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295
296 static const struct {
297 SkColor fColor;
298 const char* fName;
299 SkRegion::Op fOp;
300 } gOps[] = {
301 { SK_ColorBLACK, "Difference", SkRegion::kDifference_Op },
302 { SK_ColorRED, "Intersect", SkRegion::kIntersect_Op },
303 { 0xFF008800, "Union", SkRegion::kUnion_Op },
304 { SK_ColorBLUE, "XOR", SkRegion::kXOR_Op }
305 };
306
Mike Reed89126e42019-01-03 12:59:14 -0500307 SkFont font;
308 font.setSize(SK_Scalar1*24);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000309
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++) {
Mike Reed89126e42019-01-03 12:59:14 -0500319 canvas->drawSimpleText(gOps[op].fName, strlen(gOps[op].fName), kUTF8_SkTextEncoding,
320 SkIntToScalar(75), SkIntToScalar(50), font, SkPaint());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000321
322 this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
323
mike@reedtribe.org5fd92432011-05-05 01:59:48 +0000324 canvas->save();
325 canvas->translate(0, SkIntToScalar(200));
326 this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
327 canvas->restore();
rmistry@google.comae933ce2012-08-23 18:19:56 +0000328
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329 canvas->translate(SkIntToScalar(200), 0);
330 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000332
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400333 virtual Sample::Click* onFindClickHandler(SkScalar x, SkScalar y,
mtklein36352bf2015-03-25 18:17:31 -0700334 unsigned modi) override {
reed@google.come1ca7052013-12-17 19:22:07 +0000335 return fRect.contains(SkScalarRoundToInt(x),
halcanary96fcdcc2015-08-27 07:41:13 -0700336 SkScalarRoundToInt(y)) ? new Click(this) : nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000338
mtklein36352bf2015-03-25 18:17:31 -0700339 bool onClick(Click* click) override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340 fRect.offset(click->fICurr.fX - click->fIPrev.fX,
341 click->fICurr.fY - click->fIPrev.fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 return true;
343 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000344
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345private:
346 SkIRect fBase, fRect;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000347
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400348 typedef Sample INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000349};
350
351//////////////////////////////////////////////////////////////////////////////
352
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400353DEF_SAMPLE( return new RegionView(); )