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