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