caryclark | 63c684a | 2015-02-25 09:04:04 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2015 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 "SkPaint.h" |
| 12 | #include "SkPath.h" |
| 13 | #include "SkMatrix.h" |
| 14 | #include "SkColor.h" |
| 15 | #include "SkTDArray.h" |
| 16 | #include "SkRandom.h" |
| 17 | |
| 18 | enum RandomAddPath { |
| 19 | kMoveToPath, |
| 20 | kRMoveToPath, |
| 21 | kLineToPath, |
| 22 | kRLineToPath, |
| 23 | kQuadToPath, |
| 24 | kRQuadToPath, |
| 25 | kConicToPath, |
| 26 | kRConicToPath, |
| 27 | kCubicToPath, |
| 28 | kRCubicToPath, |
| 29 | kArcToPath, |
| 30 | kArcTo2Path, |
| 31 | kClosePath, |
| 32 | kAddArc, |
| 33 | kAddRoundRect1, |
| 34 | kAddRoundRect2, |
| 35 | kAddRRect, |
| 36 | kAddPoly, |
| 37 | kAddPath1, |
| 38 | kAddPath2, |
| 39 | kAddPath3, |
| 40 | kReverseAddPath, |
| 41 | }; |
| 42 | |
| 43 | const int kRandomAddPath_Last = kReverseAddPath; |
| 44 | |
| 45 | const char* gRandomAddPathNames[] = { |
| 46 | "kMoveToPath", |
| 47 | "kRMoveToPath", |
| 48 | "kLineToPath", |
| 49 | "kRLineToPath", |
| 50 | "kQuadToPath", |
| 51 | "kRQuadToPath", |
| 52 | "kConicToPath", |
| 53 | "kRConicToPath", |
| 54 | "kCubicToPath", |
| 55 | "kRCubicToPath", |
| 56 | "kArcToPath", |
| 57 | "kArcTo2Path", |
| 58 | "kClosePath", |
| 59 | "kAddArc", |
| 60 | "kAddRoundRect1", |
| 61 | "kAddRoundRect2", |
| 62 | "kAddRRect", |
| 63 | "kAddPoly", |
| 64 | "kAddPath1", |
| 65 | "kAddPath2", |
| 66 | "kAddPath3", |
| 67 | "kReverseAddPath", |
| 68 | }; |
| 69 | |
| 70 | enum RandomSetRRect { |
| 71 | kSetEmpty, |
| 72 | kSetRect, |
| 73 | kSetOval, |
| 74 | kSetRectXY, |
| 75 | kSetNinePatch, |
| 76 | kSetRectRadii, |
| 77 | }; |
| 78 | |
| 79 | const char* gRandomSetRRectNames[] = { |
| 80 | "kSetEmpty", |
| 81 | "kSetRect", |
| 82 | "kSetOval", |
| 83 | "kSetRectXY", |
| 84 | "kSetNinePatch", |
| 85 | "kSetRectRadii", |
| 86 | }; |
| 87 | |
| 88 | int kRandomSetRRect_Last = kSetRectRadii; |
| 89 | |
| 90 | enum RandomSetMatrix { |
| 91 | kSetIdentity, |
| 92 | kSetTranslate, |
| 93 | kSetTranslateX, |
| 94 | kSetTranslateY, |
| 95 | kSetScale, |
| 96 | kSetScaleTranslate, |
| 97 | kSetScaleX, |
| 98 | kSetScaleY, |
| 99 | kSetSkew, |
| 100 | kSetSkewTranslate, |
| 101 | kSetSkewX, |
| 102 | kSetSkewY, |
| 103 | kSetRotate, |
| 104 | kSetRotateTranslate, |
| 105 | kSetPerspectiveX, |
| 106 | kSetPerspectiveY, |
| 107 | kSetAll, |
| 108 | }; |
| 109 | |
| 110 | int kRandomSetMatrix_Last = kSetAll; |
| 111 | |
| 112 | const char* gRandomSetMatrixNames[] = { |
| 113 | "kSetIdentity", |
| 114 | "kSetTranslate", |
| 115 | "kSetTranslateX", |
| 116 | "kSetTranslateY", |
| 117 | "kSetScale", |
| 118 | "kSetScaleTranslate", |
| 119 | "kSetScaleX", |
| 120 | "kSetScaleY", |
| 121 | "kSetSkew", |
| 122 | "kSetSkewTranslate", |
| 123 | "kSetSkewX", |
| 124 | "kSetSkewY", |
| 125 | "kSetRotate", |
| 126 | "kSetRotateTranslate", |
| 127 | "kSetPerspectiveX", |
| 128 | "kSetPerspectiveY", |
| 129 | "kSetAll", |
| 130 | }; |
| 131 | |
| 132 | class FuzzPath { |
| 133 | public: |
caryclark | 94b4ee8 | 2015-03-04 12:32:22 -0800 | [diff] [blame] | 134 | FuzzPath() |
caryclark | 63c684a | 2015-02-25 09:04:04 -0800 | [diff] [blame] | 135 | : fFloatMin(0) |
| 136 | , fFloatMax(800) |
| 137 | , fAddCount(0) |
| 138 | , fPrintName(false) |
caryclark | 94b4ee8 | 2015-03-04 12:32:22 -0800 | [diff] [blame] | 139 | , fStrokeOnly(false) |
caryclark | 63c684a | 2015-02-25 09:04:04 -0800 | [diff] [blame] | 140 | , fValidate(false) |
| 141 | { |
| 142 | fTab = " "; |
| 143 | } |
| 144 | void randomize() { |
| 145 | fPathDepth = 0; |
| 146 | fPathDepthLimit = fRand.nextRangeU(1, 2); |
| 147 | fPathContourCount = fRand.nextRangeU(1, 4); |
| 148 | fPathSegmentLimit = fRand.nextRangeU(1, 8); |
| 149 | fClip = makePath(); |
| 150 | SkASSERT(!fPathDepth); |
| 151 | fMatrix = makeMatrix(); |
| 152 | fPaint = makePaint(); |
| 153 | fPathDepthLimit = fRand.nextRangeU(1, 3); |
| 154 | fPathContourCount = fRand.nextRangeU(1, 6); |
| 155 | fPathSegmentLimit = fRand.nextRangeU(1, 16); |
| 156 | fPath = makePath(); |
| 157 | SkASSERT(!fPathDepth); |
| 158 | } |
| 159 | |
| 160 | const SkPath& getClip() const { |
| 161 | return fClip; |
| 162 | } |
| 163 | |
| 164 | const SkMatrix& getMatrix() const { |
| 165 | return fMatrix; |
| 166 | } |
| 167 | |
| 168 | const SkPaint& getPaint() const { |
| 169 | return fPaint; |
| 170 | } |
| 171 | |
| 172 | const SkPath& getPath() const { |
| 173 | return fPath; |
| 174 | } |
| 175 | |
caryclark | 94b4ee8 | 2015-03-04 12:32:22 -0800 | [diff] [blame] | 176 | void setSeed(int seed) { |
| 177 | fRand.setSeed(seed); |
| 178 | } |
| 179 | |
| 180 | void setStrokeOnly() { |
| 181 | fStrokeOnly = true; |
| 182 | } |
| 183 | |
caryclark | 63c684a | 2015-02-25 09:04:04 -0800 | [diff] [blame] | 184 | private: |
| 185 | |
| 186 | SkPath::AddPathMode makeAddPathMode() { |
| 187 | return (SkPath::AddPathMode) fRand.nextRangeU(SkPath::kAppend_AddPathMode, |
| 188 | SkPath::kExtend_AddPathMode); |
| 189 | } |
| 190 | |
| 191 | RandomAddPath makeAddPathType() { |
| 192 | return (RandomAddPath) fRand.nextRangeU(0, kRandomAddPath_Last); |
| 193 | } |
| 194 | |
| 195 | SkScalar makeAngle() { |
| 196 | SkScalar angle; |
| 197 | angle = fRand.nextF(); |
| 198 | return angle; |
| 199 | } |
| 200 | |
| 201 | bool makeBool() { |
| 202 | return fRand.nextBool(); |
| 203 | } |
| 204 | |
| 205 | SkPath::Direction makeDirection() { |
| 206 | return (SkPath::Direction) fRand.nextRangeU(SkPath::kCW_Direction, SkPath::kCCW_Direction); |
| 207 | } |
| 208 | |
| 209 | SkMatrix makeMatrix() { |
| 210 | SkMatrix matrix; |
| 211 | matrix.reset(); |
| 212 | RandomSetMatrix setMatrix = (RandomSetMatrix) fRand.nextRangeU(0, kRandomSetMatrix_Last); |
| 213 | if (fPrintName) { |
| 214 | SkDebugf("%.*s%s\n", fPathDepth * 3, fTab, gRandomSetMatrixNames[setMatrix]); |
| 215 | } |
| 216 | switch (setMatrix) { |
| 217 | case kSetIdentity: |
| 218 | break; |
| 219 | case kSetTranslateX: |
| 220 | matrix.setTranslateX(makeScalar()); |
| 221 | break; |
| 222 | case kSetTranslateY: |
| 223 | matrix.setTranslateY(makeScalar()); |
| 224 | break; |
| 225 | case kSetTranslate: |
| 226 | matrix.setTranslate(makeScalar(), makeScalar()); |
| 227 | break; |
| 228 | case kSetScaleX: |
| 229 | matrix.setScaleX(makeScalar()); |
| 230 | break; |
| 231 | case kSetScaleY: |
| 232 | matrix.setScaleY(makeScalar()); |
| 233 | break; |
| 234 | case kSetScale: |
| 235 | matrix.setScale(makeScalar(), makeScalar()); |
| 236 | break; |
| 237 | case kSetScaleTranslate: |
| 238 | matrix.setScale(makeScalar(), makeScalar(), makeScalar(), makeScalar()); |
| 239 | break; |
| 240 | case kSetSkewX: |
| 241 | matrix.setSkewX(makeScalar()); |
| 242 | break; |
| 243 | case kSetSkewY: |
| 244 | matrix.setSkewY(makeScalar()); |
| 245 | break; |
| 246 | case kSetSkew: |
| 247 | matrix.setSkew(makeScalar(), makeScalar()); |
| 248 | break; |
| 249 | case kSetSkewTranslate: |
| 250 | matrix.setSkew(makeScalar(), makeScalar(), makeScalar(), makeScalar()); |
| 251 | break; |
| 252 | case kSetRotate: |
| 253 | matrix.setRotate(makeScalar()); |
| 254 | break; |
| 255 | case kSetRotateTranslate: |
| 256 | matrix.setRotate(makeScalar(), makeScalar(), makeScalar()); |
| 257 | break; |
| 258 | case kSetPerspectiveX: |
| 259 | matrix.setPerspX(makeScalar()); |
| 260 | break; |
| 261 | case kSetPerspectiveY: |
| 262 | matrix.setPerspY(makeScalar()); |
| 263 | break; |
| 264 | case kSetAll: |
| 265 | matrix.setAll(makeScalar(), makeScalar(), makeScalar(), |
| 266 | makeScalar(), makeScalar(), makeScalar(), |
| 267 | makeScalar(), makeScalar(), makeScalar()); |
| 268 | break; |
| 269 | } |
| 270 | return matrix; |
| 271 | } |
| 272 | |
| 273 | SkPaint makePaint() { |
| 274 | SkPaint paint; |
| 275 | bool antiAlias = fRand.nextBool(); |
| 276 | paint.setAntiAlias(antiAlias); |
caryclark | 94b4ee8 | 2015-03-04 12:32:22 -0800 | [diff] [blame] | 277 | SkPaint::Style style = fStrokeOnly ? SkPaint::kStroke_Style : |
| 278 | (SkPaint::Style) fRand.nextRangeU(SkPaint::kFill_Style, SkPaint::kStrokeAndFill_Style); |
caryclark | 63c684a | 2015-02-25 09:04:04 -0800 | [diff] [blame] | 279 | paint.setStyle(style); |
| 280 | SkColor color = (SkColor) fRand.nextU(); |
| 281 | paint.setColor(color); |
caryclark | 94b4ee8 | 2015-03-04 12:32:22 -0800 | [diff] [blame] | 282 | SkScalar width = fRand.nextRangeF(0, 10); |
caryclark | 63c684a | 2015-02-25 09:04:04 -0800 | [diff] [blame] | 283 | paint.setStrokeWidth(width); |
caryclark | 94b4ee8 | 2015-03-04 12:32:22 -0800 | [diff] [blame] | 284 | SkScalar miter = makeScalar(); |
caryclark | 63c684a | 2015-02-25 09:04:04 -0800 | [diff] [blame] | 285 | paint.setStrokeMiter(miter); |
| 286 | SkPaint::Cap cap = (SkPaint::Cap) fRand.nextRangeU(SkPaint::kButt_Cap, SkPaint::kSquare_Cap); |
| 287 | paint.setStrokeCap(cap); |
| 288 | SkPaint::Join join = (SkPaint::Join) fRand.nextRangeU(SkPaint::kMiter_Join, |
| 289 | SkPaint::kBevel_Join); |
| 290 | paint.setStrokeJoin(join); |
| 291 | return paint; |
| 292 | } |
| 293 | |
| 294 | SkPoint makePoint() { |
| 295 | SkPoint result; |
| 296 | makeScalarArray(2, &result.fX); |
| 297 | return result; |
| 298 | } |
| 299 | |
| 300 | void makePointArray(size_t arrayCount, SkPoint* points) { |
| 301 | for (size_t index = 0; index < arrayCount; ++index) { |
| 302 | points[index] = makePoint(); |
| 303 | } |
| 304 | } |
| 305 | |
| 306 | void makePointArray(SkTDArray<SkPoint>* points) { |
| 307 | size_t arrayCount = fRand.nextRangeU(1, 10); |
| 308 | for (size_t index = 0; index < arrayCount; ++index) { |
| 309 | *points->append() = makePoint(); |
| 310 | } |
| 311 | } |
| 312 | |
| 313 | SkRect makeRect() { |
| 314 | SkRect result; |
| 315 | makeScalarArray(4, &result.fLeft); |
| 316 | return result; |
| 317 | } |
| 318 | |
| 319 | SkRRect makeRRect() { |
| 320 | SkRRect rrect; |
| 321 | RandomSetRRect rrectType = makeSetRRectType(); |
| 322 | if (fPrintName) { |
| 323 | SkDebugf("%.*s%s\n", fPathDepth * 3, fTab, gRandomSetRRectNames[rrectType]); |
| 324 | } |
| 325 | switch (rrectType) { |
| 326 | case kSetEmpty: |
| 327 | rrect.setEmpty(); |
| 328 | break; |
| 329 | case kSetRect: { |
| 330 | SkRect rect = makeRect(); |
| 331 | rrect.setRect(rect); |
| 332 | } break; |
| 333 | case kSetOval: { |
| 334 | SkRect oval = makeRect(); |
| 335 | rrect.setOval(oval); |
| 336 | } break; |
| 337 | case kSetRectXY: { |
| 338 | SkRect rect = makeRect(); |
| 339 | SkScalar xRad = makeScalar(); |
| 340 | SkScalar yRad = makeScalar(); |
| 341 | rrect.setRectXY(rect, xRad, yRad); |
| 342 | } break; |
| 343 | case kSetNinePatch: { |
| 344 | SkRect rect = makeRect(); |
| 345 | SkScalar leftRad = makeScalar(); |
| 346 | SkScalar topRad = makeScalar(); |
| 347 | SkScalar rightRad = makeScalar(); |
| 348 | SkScalar bottomRad = makeScalar(); |
| 349 | rrect.setNinePatch(rect, leftRad, topRad, rightRad, bottomRad); |
| 350 | SkDebugf(""); // keep locals in scope |
| 351 | } break; |
| 352 | case kSetRectRadii: { |
| 353 | SkRect rect = makeRect(); |
| 354 | SkVector radii[4]; |
| 355 | makeVectorArray(SK_ARRAY_COUNT(radii), radii); |
| 356 | rrect.setRectRadii(rect, radii); |
| 357 | } break; |
| 358 | } |
| 359 | return rrect; |
| 360 | } |
| 361 | |
| 362 | SkPath makePath() { |
| 363 | SkPath path; |
| 364 | for (uint32_t cIndex = 0; cIndex < fPathContourCount; ++cIndex) { |
| 365 | uint32_t segments = makeSegmentCount(); |
| 366 | for (uint32_t sIndex = 0; sIndex < segments; ++sIndex) { |
| 367 | RandomAddPath addPathType = makeAddPathType(); |
| 368 | ++fAddCount; |
| 369 | if (fPrintName) { |
| 370 | SkDebugf("%.*s%s\n", fPathDepth * 3, fTab, |
| 371 | gRandomAddPathNames[addPathType]); |
| 372 | } |
| 373 | switch (addPathType) { |
| 374 | case kAddArc: { |
| 375 | SkRect oval = makeRect(); |
| 376 | SkScalar startAngle = makeAngle(); |
| 377 | SkScalar sweepAngle = makeAngle(); |
| 378 | path.addArc(oval, startAngle, sweepAngle); |
| 379 | validate(path); |
| 380 | } break; |
| 381 | case kAddRoundRect1: { |
| 382 | SkRect rect = makeRect(); |
| 383 | SkScalar rx = makeScalar(), ry = makeScalar(); |
| 384 | SkPath::Direction dir = makeDirection(); |
| 385 | path.addRoundRect(rect, rx, ry, dir); |
| 386 | validate(path); |
| 387 | } break; |
| 388 | case kAddRoundRect2: { |
| 389 | SkRect rect = makeRect(); |
| 390 | SkScalar radii[8]; |
| 391 | makeScalarArray(SK_ARRAY_COUNT(radii), radii); |
| 392 | SkPath::Direction dir = makeDirection(); |
| 393 | path.addRoundRect(rect, radii, dir); |
| 394 | validate(path); |
| 395 | } break; |
| 396 | case kAddRRect: { |
| 397 | SkRRect rrect = makeRRect(); |
| 398 | SkPath::Direction dir = makeDirection(); |
| 399 | path.addRRect(rrect, dir); |
| 400 | validate(path); |
| 401 | } break; |
| 402 | case kAddPoly: { |
| 403 | SkTDArray<SkPoint> points; |
| 404 | makePointArray(&points); |
| 405 | bool close = makeBool(); |
| 406 | path.addPoly(&points[0], points.count(), close); |
| 407 | validate(path); |
| 408 | } break; |
| 409 | case kAddPath1: |
| 410 | if (fPathDepth < fPathDepthLimit) { |
| 411 | ++fPathDepth; |
| 412 | SkPath src = makePath(); |
| 413 | validate(src); |
| 414 | SkScalar dx = makeScalar(); |
| 415 | SkScalar dy = makeScalar(); |
| 416 | SkPath::AddPathMode mode = makeAddPathMode(); |
| 417 | path.addPath(src, dx, dy, mode); |
| 418 | --fPathDepth; |
| 419 | validate(path); |
caryclark | 94b4ee8 | 2015-03-04 12:32:22 -0800 | [diff] [blame] | 420 | } |
caryclark | 63c684a | 2015-02-25 09:04:04 -0800 | [diff] [blame] | 421 | break; |
| 422 | case kAddPath2: |
| 423 | if (fPathDepth < fPathDepthLimit) { |
| 424 | ++fPathDepth; |
| 425 | SkPath src = makePath(); |
| 426 | validate(src); |
| 427 | SkPath::AddPathMode mode = makeAddPathMode(); |
| 428 | path.addPath(src, mode); |
| 429 | --fPathDepth; |
| 430 | validate(path); |
| 431 | } |
| 432 | break; |
| 433 | case kAddPath3: |
| 434 | if (fPathDepth < fPathDepthLimit) { |
| 435 | ++fPathDepth; |
| 436 | SkPath src = makePath(); |
| 437 | validate(src); |
| 438 | SkMatrix matrix = makeMatrix(); |
| 439 | SkPath::AddPathMode mode = makeAddPathMode(); |
| 440 | path.addPath(src, matrix, mode); |
| 441 | --fPathDepth; |
| 442 | validate(path); |
| 443 | } |
| 444 | break; |
| 445 | case kReverseAddPath: |
| 446 | if (fPathDepth < fPathDepthLimit) { |
| 447 | ++fPathDepth; |
| 448 | SkPath src = makePath(); |
| 449 | validate(src); |
| 450 | path.reverseAddPath(src); |
| 451 | --fPathDepth; |
| 452 | validate(path); |
| 453 | } |
| 454 | break; |
| 455 | case kMoveToPath: { |
| 456 | SkScalar x = makeScalar(); |
| 457 | SkScalar y = makeScalar(); |
| 458 | path.moveTo(x, y); |
| 459 | validate(path); |
| 460 | } break; |
| 461 | case kRMoveToPath: { |
| 462 | SkScalar x = makeScalar(); |
| 463 | SkScalar y = makeScalar(); |
| 464 | path.rMoveTo(x, y); |
| 465 | validate(path); |
| 466 | } break; |
| 467 | case kLineToPath: { |
| 468 | SkScalar x = makeScalar(); |
| 469 | SkScalar y = makeScalar(); |
| 470 | path.lineTo(x, y); |
| 471 | validate(path); |
| 472 | } break; |
| 473 | case kRLineToPath: { |
| 474 | SkScalar x = makeScalar(); |
| 475 | SkScalar y = makeScalar(); |
| 476 | path.rLineTo(x, y); |
| 477 | validate(path); |
| 478 | } break; |
| 479 | case kQuadToPath: { |
| 480 | SkPoint pt[2]; |
| 481 | makePointArray(SK_ARRAY_COUNT(pt), pt); |
| 482 | path.quadTo(pt[0], pt[1]); |
| 483 | validate(path); |
| 484 | } break; |
| 485 | case kRQuadToPath: { |
| 486 | SkPoint pt[2]; |
| 487 | makePointArray(SK_ARRAY_COUNT(pt), pt); |
| 488 | path.rQuadTo(pt[0].fX, pt[0].fY, pt[1].fX, pt[1].fY); |
| 489 | validate(path); |
| 490 | } break; |
| 491 | case kConicToPath: { |
| 492 | SkPoint pt[2]; |
| 493 | makePointArray(SK_ARRAY_COUNT(pt), pt); |
| 494 | SkScalar weight = makeScalar(); |
| 495 | path.conicTo(pt[0], pt[1], weight); |
| 496 | validate(path); |
| 497 | } break; |
| 498 | case kRConicToPath: { |
| 499 | SkPoint pt[2]; |
| 500 | makePointArray(SK_ARRAY_COUNT(pt), pt); |
| 501 | SkScalar weight = makeScalar(); |
| 502 | path.rConicTo(pt[0].fX, pt[0].fY, pt[1].fX, pt[1].fY, weight); |
| 503 | validate(path); |
| 504 | } break; |
| 505 | case kCubicToPath: { |
| 506 | SkPoint pt[3]; |
| 507 | makePointArray(SK_ARRAY_COUNT(pt), pt); |
| 508 | path.cubicTo(pt[0], pt[1], pt[2]); |
| 509 | validate(path); |
| 510 | } break; |
| 511 | case kRCubicToPath: { |
| 512 | SkPoint pt[3]; |
| 513 | makePointArray(SK_ARRAY_COUNT(pt), pt); |
| 514 | path.rCubicTo(pt[0].fX, pt[0].fY, pt[1].fX, pt[1].fY, pt[2].fX, pt[2].fY); |
| 515 | validate(path); |
| 516 | } break; |
| 517 | case kArcToPath: { |
| 518 | SkPoint pt[2]; |
| 519 | makePointArray(SK_ARRAY_COUNT(pt), pt); |
| 520 | SkScalar radius = makeScalar(); |
| 521 | path.arcTo(pt[0], pt[1], radius); |
| 522 | validate(path); |
| 523 | } break; |
| 524 | case kArcTo2Path: { |
| 525 | SkRect oval = makeRect(); |
| 526 | SkScalar startAngle = makeAngle(); |
| 527 | SkScalar sweepAngle = makeAngle(); |
| 528 | bool forceMoveTo = makeBool(); |
| 529 | path.arcTo(oval, startAngle, sweepAngle, forceMoveTo); |
| 530 | validate(path); |
| 531 | } break; |
| 532 | case kClosePath: |
| 533 | path.close(); |
| 534 | validate(path); |
| 535 | break; |
| 536 | } |
| 537 | } |
| 538 | } |
| 539 | return path; |
| 540 | } |
| 541 | |
| 542 | uint32_t makeSegmentCount() { |
| 543 | return fRand.nextRangeU(1, fPathSegmentLimit); |
| 544 | } |
| 545 | |
| 546 | RandomSetRRect makeSetRRectType() { |
| 547 | return (RandomSetRRect) fRand.nextRangeU(0, kRandomSetRRect_Last); |
| 548 | } |
| 549 | |
| 550 | SkScalar makeScalar() { |
| 551 | SkScalar scalar; |
| 552 | scalar = fRand.nextRangeF(fFloatMin, fFloatMax); |
| 553 | return scalar; |
| 554 | } |
| 555 | |
| 556 | void makeScalarArray(size_t arrayCount, SkScalar* array) { |
| 557 | for (size_t index = 0; index < arrayCount; ++index) { |
| 558 | array[index] = makeScalar(); |
| 559 | } |
| 560 | } |
| 561 | |
| 562 | void makeVectorArray(size_t arrayCount, SkVector* array) { |
| 563 | for (size_t index = 0; index < arrayCount; ++index) { |
| 564 | array[index] = makeVector(); |
| 565 | } |
| 566 | } |
| 567 | |
| 568 | SkVector makeVector() { |
| 569 | SkVector result; |
| 570 | makeScalarArray(2, &result.fX); |
| 571 | return result; |
| 572 | } |
| 573 | |
| 574 | void validate(const SkPath& path) { |
| 575 | if (fValidate) { |
| 576 | SkDEBUGCODE(path.experimentalValidateRef()); |
| 577 | } |
| 578 | } |
| 579 | |
| 580 | SkRandom fRand; |
| 581 | SkMatrix fMatrix; |
| 582 | SkPath fClip; |
| 583 | SkPaint fPaint; |
| 584 | SkPath fPath; |
| 585 | SkScalar fFloatMin; |
| 586 | SkScalar fFloatMax; |
| 587 | uint32_t fPathContourCount; |
| 588 | int fPathDepth; |
| 589 | int fPathDepthLimit; |
| 590 | uint32_t fPathSegmentLimit; |
| 591 | int fAddCount; |
| 592 | bool fPrintName; |
caryclark | 94b4ee8 | 2015-03-04 12:32:22 -0800 | [diff] [blame] | 593 | bool fStrokeOnly; |
caryclark | 63c684a | 2015-02-25 09:04:04 -0800 | [diff] [blame] | 594 | bool fValidate; |
| 595 | const char* fTab; |
| 596 | }; |
| 597 | |
caryclark | 63c684a | 2015-02-25 09:04:04 -0800 | [diff] [blame] | 598 | static bool contains_only_moveTo(const SkPath& path) { |
| 599 | int verbCount = path.countVerbs(); |
| 600 | if (verbCount == 0) { |
| 601 | return true; |
| 602 | } |
| 603 | SkTDArray<uint8_t> verbs; |
| 604 | verbs.setCount(verbCount); |
| 605 | SkDEBUGCODE(int getVerbResult = ) path.getVerbs(verbs.begin(), verbCount); |
| 606 | SkASSERT(getVerbResult == verbCount); |
| 607 | for (int index = 0; index < verbCount; ++index) { |
| 608 | if (verbs[index] != SkPath::kMove_Verb) { |
| 609 | return false; |
| 610 | } |
| 611 | } |
| 612 | return true; |
| 613 | } |
| 614 | |
caryclark | 94b4ee8 | 2015-03-04 12:32:22 -0800 | [diff] [blame] | 615 | #include "SkGraphics.h" |
| 616 | #include "SkSurface.h" |
| 617 | #include "SkTaskGroup.h" |
| 618 | #include "SkTDArray.h" |
| 619 | |
caryclark | 94b4ee8 | 2015-03-04 12:32:22 -0800 | [diff] [blame] | 620 | static void path_fuzz_stroker(SkBitmap* bitmap, int seed) { |
mtklein | 00b621c | 2015-06-17 15:26:15 -0700 | [diff] [blame] | 621 | sk_parallel_for(100, [&](int i) { |
| 622 | int localSeed = seed + i; |
| 623 | |
| 624 | FuzzPath fuzzPath; |
| 625 | fuzzPath.setStrokeOnly(); |
| 626 | fuzzPath.setSeed(localSeed); |
| 627 | fuzzPath.randomize(); |
| 628 | const SkPath& path = fuzzPath.getPath(); |
| 629 | const SkPaint& paint = fuzzPath.getPaint(); |
| 630 | const SkImageInfo& info = bitmap->info(); |
| 631 | SkCanvas* canvas( |
| 632 | SkCanvas::NewRasterDirect(info, bitmap->getPixels(), bitmap->rowBytes())); |
| 633 | int w = info.width() / 4; |
| 634 | int h = info.height() / 4; |
| 635 | int x = localSeed / 4 % 4; |
| 636 | int y = localSeed % 4; |
| 637 | SkRect clipBounds = SkRect::MakeXYWH(SkIntToScalar(x) * w, SkIntToScalar(y) * h, |
| 638 | SkIntToScalar(w), SkIntToScalar(h)); |
| 639 | canvas->save(); |
| 640 | canvas->clipRect(clipBounds); |
| 641 | canvas->translate(SkIntToScalar(x) * w, SkIntToScalar(y) * h); |
| 642 | canvas->drawPath(path, paint); |
| 643 | canvas->restore(); |
| 644 | }); |
caryclark | 94b4ee8 | 2015-03-04 12:32:22 -0800 | [diff] [blame] | 645 | } |
| 646 | |
caryclark | 63c684a | 2015-02-25 09:04:04 -0800 | [diff] [blame] | 647 | class PathFuzzView : public SampleView { |
| 648 | public: |
caryclark | 94b4ee8 | 2015-03-04 12:32:22 -0800 | [diff] [blame] | 649 | PathFuzzView() |
| 650 | : fOneDraw(false) |
| 651 | { |
caryclark | 63c684a | 2015-02-25 09:04:04 -0800 | [diff] [blame] | 652 | } |
| 653 | protected: |
| 654 | // overrides from SkEventSink |
| 655 | virtual bool onQuery(SkEvent* evt) { |
| 656 | if (SampleCode::TitleQ(*evt)) { |
| 657 | SampleCode::TitleR(evt, "PathFuzzer"); |
| 658 | return true; |
| 659 | } |
| 660 | return this->INHERITED::onQuery(evt); |
| 661 | } |
| 662 | |
mtklein | 36352bf | 2015-03-25 18:17:31 -0700 | [diff] [blame] | 663 | void onOnceBeforeDraw() override { |
caryclark | 94b4ee8 | 2015-03-04 12:32:22 -0800 | [diff] [blame] | 664 | fIndex = 0; |
mtklein | 00b621c | 2015-06-17 15:26:15 -0700 | [diff] [blame] | 665 | SkImageInfo info(SkImageInfo::MakeN32Premul(SkScalarRoundToInt(width()), |
caryclark | 94b4ee8 | 2015-03-04 12:32:22 -0800 | [diff] [blame] | 666 | SkScalarRoundToInt(height()))); |
| 667 | offscreen.allocPixels(info); |
| 668 | path_fuzz_stroker(&offscreen, fIndex); |
| 669 | } |
| 670 | |
caryclark | 63c684a | 2015-02-25 09:04:04 -0800 | [diff] [blame] | 671 | virtual void onDrawContent(SkCanvas* canvas) { |
caryclark | 94b4ee8 | 2015-03-04 12:32:22 -0800 | [diff] [blame] | 672 | if (fOneDraw) { |
| 673 | fuzzPath.randomize(); |
| 674 | const SkPath& path = fuzzPath.getPath(); |
| 675 | const SkPaint& paint = fuzzPath.getPaint(); |
| 676 | const SkPath& clip = fuzzPath.getClip(); |
| 677 | const SkMatrix& matrix = fuzzPath.getMatrix(); |
| 678 | if (!contains_only_moveTo(clip)) { |
| 679 | canvas->clipPath(clip); |
| 680 | } |
| 681 | canvas->setMatrix(matrix); |
| 682 | canvas->drawPath(path, paint); |
| 683 | } else { |
| 684 | path_fuzz_stroker(&offscreen, fIndex += 100); |
| 685 | canvas->drawBitmap(offscreen, 0, 0); |
caryclark | 63c684a | 2015-02-25 09:04:04 -0800 | [diff] [blame] | 686 | } |
caryclark | 63c684a | 2015-02-25 09:04:04 -0800 | [diff] [blame] | 687 | this->inval(NULL); |
caryclark | 63c684a | 2015-02-25 09:04:04 -0800 | [diff] [blame] | 688 | } |
| 689 | |
| 690 | private: |
caryclark | 94b4ee8 | 2015-03-04 12:32:22 -0800 | [diff] [blame] | 691 | int fIndex; |
| 692 | SkBitmap offscreen; |
caryclark | 63c684a | 2015-02-25 09:04:04 -0800 | [diff] [blame] | 693 | FuzzPath fuzzPath; |
caryclark | 94b4ee8 | 2015-03-04 12:32:22 -0800 | [diff] [blame] | 694 | bool fOneDraw; |
caryclark | 63c684a | 2015-02-25 09:04:04 -0800 | [diff] [blame] | 695 | typedef SkView INHERITED; |
| 696 | }; |
| 697 | |
caryclark | 63c684a | 2015-02-25 09:04:04 -0800 | [diff] [blame] | 698 | static SkView* MyFactory() { return new PathFuzzView; } |
| 699 | static SkViewRegister reg(MyFactory); |
caryclark | 94b4ee8 | 2015-03-04 12:32:22 -0800 | [diff] [blame] | 700 | |
| 701 | |