1 /*
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 */
7
8 #include "SampleCode.h"
9 #include "SkView.h"
10 #include "SkCanvas.h"
11 #include "SkGradientShader.h"
12 #include "SkPath.h"
13 #include "SkRegion.h"
14 #include "SkShader.h"
15 #include "SkUtils.h"
16
17 #include <math.h>
18
test_strokerect(SkCanvas * canvas)19 static void test_strokerect(SkCanvas* canvas) {
20 int width = 100;
21 int height = 100;
22
23 SkBitmap bitmap;
24 bitmap.allocPixels(SkImageInfo::MakeA8(width*2, height*2));
25 bitmap.eraseColor(SK_ColorTRANSPARENT);
26
27 SkScalar dx = 20;
28 SkScalar dy = 20;
29
30 SkPath path;
31 path.addRect(0.0f, 0.0f,
32 SkIntToScalar(width), SkIntToScalar(height),
33 SkPath::kCW_Direction);
34 SkRect r = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
35
36 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
44 c.clear(SK_ColorTRANSPARENT);
45 c.drawRect(r, paint);
46 canvas->drawBitmap(bitmap, 0, 0, nullptr);
47
48 // use the path
49 c.clear(SK_ColorTRANSPARENT);
50 c.drawPath(path, paint);
51 canvas->drawBitmap(bitmap, SkIntToScalar(2*width), 0, nullptr);
52 }
53
drawFadingText(SkCanvas * canvas,const char * text,size_t len,SkScalar x,SkScalar y,const SkPaint & paint)54 static 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;
59 SkPaint::FontMetrics fm;
60
61 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
68 canvas->saveLayer(&bounds, nullptr);
69 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.
79 const SkScalar pos[] = { 0, 0.9f, SK_Scalar1 };
80
81 SkPaint p;
82 p.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 3, SkShader::kClamp_TileMode));
83 p.setBlendMode(SkBlendMode::kDstIn);
84 canvas->drawRect(bounds, p);
85
86 canvas->restore();
87 }
88
test_text(SkCanvas * canvas)89 static void test_text(SkCanvas* canvas) {
90 SkPaint paint;
91 paint.setAntiAlias(true);
92 paint.setTextSize(20);
93
94 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 };
106 paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos,
107 SK_ARRAY_COUNT(colors),
108 SkShader::kClamp_TileMode));
109 canvas->drawText(str, len, x, y, paint);
110
111 y += 20;
112 paint.setShader(nullptr);
113 drawFadingText(canvas, str, len, x, y, paint);
114 }
115
116 #ifdef SK_DEBUG
make_rgn(SkRegion * rgn,int left,int top,int right,int bottom,int count,int32_t runs[])117 static void make_rgn(SkRegion* rgn, int left, int top, int right, int bottom,
118 int count, int32_t runs[]) {
119 SkIRect r;
120 r.set(left, top, right, bottom);
121
122 rgn->debugSetRuns(runs, count);
123 SkASSERT(rgn->getBounds() == r);
124 }
125
test_union_bug_1505668(SkRegion * ra,SkRegion * rb,SkRegion * rc)126 static void test_union_bug_1505668(SkRegion* ra, SkRegion* rb, SkRegion* rc) {
127 static int32_t dataA[] = {
128 0x00000001,
129 0x000001dd, 2, 0x00000001, 0x0000000c, 0x0000000d, 0x00000025, 0x7fffffff,
130 0x000001de, 1, 0x00000001, 0x00000025, 0x7fffffff,
131 0x000004b3, 1, 0x00000001, 0x00000026, 0x7fffffff,
132 0x000004b4, 1, 0x0000000c, 0x00000026, 0x7fffffff,
133 0x00000579, 1, 0x00000000, 0x0000013a, 0x7fffffff,
134 0x000005d8, 1, 0x00000000, 0x0000013b, 0x7fffffff,
135 0x7fffffff
136 };
137 make_rgn(ra, 0, 1, 315, 1496, SK_ARRAY_COUNT(dataA), dataA);
138
139 static int32_t dataB[] = {
140 0x000000b6,
141 0x000000c4, 1, 0x000000a1, 0x000000f0, 0x7fffffff,
142 0x000000d6, 0, 0x7fffffff,
143 0x000000e4, 2, 0x00000070, 0x00000079, 0x000000a1, 0x000000b0, 0x7fffffff,
144 0x000000e6, 0, 0x7fffffff,
145 0x000000f4, 2, 0x00000070, 0x00000079, 0x000000a1, 0x000000b0, 0x7fffffff,
146 0x000000f6, 0, 0x7fffffff,
147 0x00000104, 1, 0x000000a1, 0x000000b0, 0x7fffffff,
148 0x7fffffff
149 };
150 make_rgn(rb, 112, 182, 240, 260, SK_ARRAY_COUNT(dataB), dataB);
151
152 rc->op(*ra, *rb, SkRegion::kUnion_Op);
153 }
154 #endif
155
scale_rect(SkIRect * dst,const SkIRect & src,float scale)156 static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
157 dst->fLeft = (int)::roundf(src.fLeft * scale);
158 dst->fTop = (int)::roundf(src.fTop * scale);
159 dst->fRight = (int)::roundf(src.fRight * scale);
160 dst->fBottom = (int)::roundf(src.fBottom * scale);
161 }
162
scale_rgn(SkRegion * dst,const SkRegion & src,float scale)163 static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
164 SkRegion tmp;
165 SkRegion::Iterator iter(src);
166
167 for (; !iter.done(); iter.next()) {
168 SkIRect r;
169 scale_rect(&r, iter.rect(), scale);
170 tmp.op(r, SkRegion::kUnion_Op);
171 }
172 dst->swap(tmp);
173 }
174
paint_rgn(SkCanvas * canvas,const SkRegion & rgn,const SkPaint & paint)175 static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn,
176 const SkPaint& paint) {
177 SkRegion scaled;
178 scale_rgn(&scaled, rgn, 0.5f);
179
180 SkRegion::Iterator iter(rgn);
181
182 for (; !iter.done(); iter.next())
183 {
184 SkRect r;
185 r.set(iter.rect());
186 canvas->drawRect(r, paint);
187 }
188 }
189
190 class RegionView : public SampleView {
191 public:
RegionView()192 RegionView() {
193 fBase.set(100, 100, 150, 150);
194 fRect = fBase;
195 fRect.inset(5, 5);
196 fRect.offset(25, 25);
197 this->setBGColor(0xFFDDDDDD);
198 }
199
build_base_rgn(SkRegion * rgn)200 void build_base_rgn(SkRegion* rgn) {
201 rgn->setRect(fBase);
202 SkIRect r = fBase;
203 r.offset(75, 20);
204 rgn->op(r, SkRegion::kUnion_Op);
205 }
206
build_rgn(SkRegion * rgn,SkRegion::Op op)207 void build_rgn(SkRegion* rgn, SkRegion::Op op) {
208 build_base_rgn(rgn);
209 rgn->op(fRect, op);
210 }
211
212
213 protected:
214 // overrides from SkEventSink
onQuery(SkEvent * evt)215 bool onQuery(SkEvent* evt) override {
216 if (SampleCode::TitleQ(*evt)) {
217 SampleCode::TitleR(evt, "Regions");
218 return true;
219 }
220 return this->INHERITED::onQuery(evt);
221 }
222
drawstr(SkCanvas * canvas,const char text[],const SkPoint & loc,bool hilite)223 static void drawstr(SkCanvas* canvas, const char text[], const SkPoint& loc,
224 bool hilite) {
225 SkPaint paint;
226 paint.setAntiAlias(true);
227 paint.setTextSize(SkIntToScalar(20));
228 paint.setColor(hilite ? SK_ColorRED : 0x40FF0000);
229 canvas->drawText(text, strlen(text), loc.fX, loc.fY, paint);
230 }
231
drawPredicates(SkCanvas * canvas,const SkPoint pts[])232 void drawPredicates(SkCanvas* canvas, const SkPoint pts[]) {
233 SkRegion rgn;
234 build_base_rgn(&rgn);
235
236 drawstr(canvas, "Intersects", pts[0], rgn.intersects(fRect));
237 drawstr(canvas, "Contains", pts[1], rgn.contains(fRect));
238 }
239
drawOrig(SkCanvas * canvas,bool bg)240 void drawOrig(SkCanvas* canvas, bool bg) {
241 SkRect r;
242 SkPaint paint;
243
244 paint.setStyle(SkPaint::kStroke_Style);
245 if (bg)
246 paint.setColor(0xFFBBBBBB);
247
248 SkRegion rgn;
249 build_base_rgn(&rgn);
250 paint_rgn(canvas, rgn, paint);
251
252 r.set(fRect);
253 canvas->drawRect(r, paint);
254 }
255
drawRgnOped(SkCanvas * canvas,SkRegion::Op op,SkColor color)256 void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
257 SkRegion rgn;
258
259 this->build_rgn(&rgn, op);
260
261 {
262 SkRegion tmp, tmp2(rgn);
263
264 tmp = tmp2;
265 tmp.translate(5, -3);
266
267 {
268 char buffer[1000];
269 SkDEBUGCODE(size_t size = ) tmp.writeToMemory(nullptr);
270 SkASSERT(size <= sizeof(buffer));
271 SkDEBUGCODE(size_t size2 = ) tmp.writeToMemory(buffer);
272 SkASSERT(size == size2);
273
274 SkRegion tmp3;
275 SkDEBUGCODE(size2 = ) tmp3.readFromMemory(buffer, 1000);
276 SkASSERT(size == size2);
277
278 SkASSERT(tmp3 == tmp);
279 }
280
281 rgn.translate(20, 30, &tmp);
282 SkASSERT(rgn.isEmpty() || tmp != rgn);
283 tmp.translate(-20, -30);
284 SkASSERT(tmp == rgn);
285 }
286
287 this->drawOrig(canvas, true);
288
289 SkPaint paint;
290 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
291 paint_rgn(canvas, rgn, paint);
292
293 paint.setStyle(SkPaint::kStroke_Style);
294 paint.setColor(color);
295 paint_rgn(canvas, rgn, paint);
296 }
297
drawPathOped(SkCanvas * canvas,SkRegion::Op op,SkColor color)298 void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
299 SkRegion rgn;
300 SkPath path;
301
302 this->build_rgn(&rgn, op);
303 rgn.getBoundaryPath(&path);
304
305 this->drawOrig(canvas, true);
306
307 SkPaint paint;
308
309 paint.setStyle(SkPaint::kFill_Style);
310 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
311 canvas->drawPath(path, paint);
312 paint.setColor(color);
313 paint.setStyle(SkPaint::kStroke_Style);
314 canvas->drawPath(path, paint);
315 }
316
onDrawContent(SkCanvas * canvas)317 void onDrawContent(SkCanvas* canvas) override {
318 if (false) { // avoid bit rot, suppress warning
319 test_strokerect(canvas);
320 return;
321 }
322 if (false) { // avoid bit rot, suppress warning
323 test_text(canvas);
324 return;
325 }
326 #ifdef SK_DEBUG
327 if (true) {
328 SkRegion a, b, c;
329 test_union_bug_1505668(&a, &b, &c);
330
331 if (false) { // draw the result of the test
332 SkPaint paint;
333
334 canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
335 paint.setColor(SK_ColorRED);
336 paint_rgn(canvas, a, paint);
337 paint.setColor(0x800000FF);
338 paint_rgn(canvas, b, paint);
339 paint.setColor(SK_ColorBLACK);
340 paint.setStyle(SkPaint::kStroke_Style);
341 // paint_rgn(canvas, c, paint);
342 return;
343 }
344 }
345 #endif
346 const SkPoint origins[] = {
347 { 30*SK_Scalar1, 50*SK_Scalar1 },
348 { 150*SK_Scalar1, 50*SK_Scalar1 },
349 };
350 this->drawPredicates(canvas, origins);
351
352 static const struct {
353 SkColor fColor;
354 const char* fName;
355 SkRegion::Op fOp;
356 } gOps[] = {
357 { SK_ColorBLACK, "Difference", SkRegion::kDifference_Op },
358 { SK_ColorRED, "Intersect", SkRegion::kIntersect_Op },
359 { 0xFF008800, "Union", SkRegion::kUnion_Op },
360 { SK_ColorBLUE, "XOR", SkRegion::kXOR_Op }
361 };
362
363 SkPaint textPaint;
364 textPaint.setAntiAlias(true);
365 textPaint.setTextSize(SK_Scalar1*24);
366
367 this->drawOrig(canvas, false);
368 canvas->save();
369 canvas->translate(SkIntToScalar(200), 0);
370 this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK);
371 canvas->restore();
372
373 canvas->translate(0, SkIntToScalar(200));
374
375 for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); op++) {
376 canvas->drawText(gOps[op].fName, strlen(gOps[op].fName), SkIntToScalar(75), SkIntToScalar(50), textPaint);
377
378 this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
379
380 canvas->save();
381 canvas->translate(0, SkIntToScalar(200));
382 this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
383 canvas->restore();
384
385 canvas->translate(SkIntToScalar(200), 0);
386 }
387 }
388
onFindClickHandler(SkScalar x,SkScalar y,unsigned modi)389 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y,
390 unsigned modi) override {
391 return fRect.contains(SkScalarRoundToInt(x),
392 SkScalarRoundToInt(y)) ? new Click(this) : nullptr;
393 }
394
onClick(Click * click)395 bool onClick(Click* click) override {
396 fRect.offset(click->fICurr.fX - click->fIPrev.fX,
397 click->fICurr.fY - click->fIPrev.fY);
398 this->inval(nullptr);
399 return true;
400 }
401
402 private:
403 SkIRect fBase, fRect;
404
405 typedef SampleView INHERITED;
406 };
407
408 //////////////////////////////////////////////////////////////////////////////
409
MyFactory()410 static SkView* MyFactory() { return new RegionView; }
411 static SkViewRegister reg(MyFactory);
412