| OLD | NEW |
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2006 The Android Open Source Project | 3 * Copyright 2006 The Android Open Source Project |
| 4 * | 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 | 9 |
| 10 #include "SkBuffer.h" | 10 #include "SkBuffer.h" |
| (...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 352 | 352 |
| 353 A rectangle cycles up/right/down/left or up/left/down/right. | 353 A rectangle cycles up/right/down/left or up/left/down/right. |
| 354 | 354 |
| 355 The test fails if: | 355 The test fails if: |
| 356 The path is closed, and followed by a line. | 356 The path is closed, and followed by a line. |
| 357 A second move creates a new endpoint. | 357 A second move creates a new endpoint. |
| 358 A diagonal line is parsed. | 358 A diagonal line is parsed. |
| 359 There's more than four changes of direction. | 359 There's more than four changes of direction. |
| 360 There's a discontinuity on the line (e.g., a move in the middle) | 360 There's a discontinuity on the line (e.g., a move in the middle) |
| 361 The line reverses direction. | 361 The line reverses direction. |
| 362 The rectangle doesn't complete a cycle. | |
| 363 The path contains a quadratic or cubic. | 362 The path contains a quadratic or cubic. |
| 364 The path contains fewer than four points. | 363 The path contains fewer than four points. |
| 365 The final point isn't equal to the first point. | 364 *The rectangle doesn't complete a cycle. |
| 365 *The final point isn't equal to the first point. |
| 366 |
| 367 *These last two conditions we relax if we have a 3-edge path that would |
| 368 form a rectangle if it were closed (as we do when we fill a path) |
| 366 | 369 |
| 367 It's OK if the path has: | 370 It's OK if the path has: |
| 368 Several colinear line segments composing a rectangle side. | 371 Several colinear line segments composing a rectangle side. |
| 369 Single points on the rectangle side. | 372 Single points on the rectangle side. |
| 370 | 373 |
| 371 The direction takes advantage of the corners found since opposite sides | 374 The direction takes advantage of the corners found since opposite sides |
| 372 must travel in opposite directions. | 375 must travel in opposite directions. |
| 373 | 376 |
| 374 FIXME: Allow colinear quads and cubics to be treated like lines. | 377 FIXME: Allow colinear quads and cubics to be treated like lines. |
| 375 FIXME: If the API passes fill-only, return true if the filled stroke | 378 FIXME: If the API passes fill-only, return true if the filled stroke |
| 376 is a rectangle, though the caller failed to close the path. | 379 is a rectangle, though the caller failed to close the path. |
| 380 |
| 381 first,last,next direction state-machine: |
| 382 0x1 is set if the segment is horizontal |
| 383 0x2 is set if the segment is moving to the right or down |
| 384 thus: |
| 385 two directions are opposites iff (dirA ^ dirB) == 0x2 |
| 386 two directions are perpendicular iff (dirA ^ dirB) == 0x1 |
| 387 |
| 377 */ | 388 */ |
| 389 static int rect_make_dir(SkScalar dx, SkScalar dy) { |
| 390 return ((0 != dx) << 0) | ((dx > 0 || dy > 0) << 1); |
| 391 } |
| 378 bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts
Ptr, | 392 bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts
Ptr, |
| 379 bool* isClosed, Direction* direction) const { | 393 bool* isClosed, Direction* direction) const { |
| 380 int corners = 0; | 394 int corners = 0; |
| 381 SkPoint first, last; | 395 SkPoint first, last; |
| 382 const SkPoint* pts = *ptsPtr; | 396 const SkPoint* pts = *ptsPtr; |
| 383 const SkPoint* savePts = NULL; | 397 const SkPoint* savePts = NULL; |
| 384 first.set(0, 0); | 398 first.set(0, 0); |
| 385 last.set(0, 0); | 399 last.set(0, 0); |
| 386 int firstDirection = 0; | 400 int firstDirection = 0; |
| 387 int lastDirection = 0; | 401 int lastDirection = 0; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 400 SkScalar top = last.fY; | 414 SkScalar top = last.fY; |
| 401 SkScalar right = pts->fX; | 415 SkScalar right = pts->fX; |
| 402 SkScalar bottom = pts->fY; | 416 SkScalar bottom = pts->fY; |
| 403 ++pts; | 417 ++pts; |
| 404 if (left != right && top != bottom) { | 418 if (left != right && top != bottom) { |
| 405 return false; // diagonal | 419 return false; // diagonal |
| 406 } | 420 } |
| 407 if (left == right && top == bottom) { | 421 if (left == right && top == bottom) { |
| 408 break; // single point on side OK | 422 break; // single point on side OK |
| 409 } | 423 } |
| 410 nextDirection = (left != right) << 0 | | 424 nextDirection = rect_make_dir(right - left, bottom - top); |
| 411 (left < right || top < bottom) << 1; | |
| 412 if (0 == corners) { | 425 if (0 == corners) { |
| 413 firstDirection = nextDirection; | 426 firstDirection = nextDirection; |
| 414 first = last; | 427 first = last; |
| 415 last = pts[-1]; | 428 last = pts[-1]; |
| 416 corners = 1; | 429 corners = 1; |
| 417 closedOrMoved = false; | 430 closedOrMoved = false; |
| 418 break; | 431 break; |
| 419 } | 432 } |
| 420 if (closedOrMoved) { | 433 if (closedOrMoved) { |
| 421 return false; // closed followed by a line | 434 return false; // closed followed by a line |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 453 break; | 466 break; |
| 454 default: | 467 default: |
| 455 SkDEBUGFAIL("unexpected verb"); | 468 SkDEBUGFAIL("unexpected verb"); |
| 456 break; | 469 break; |
| 457 } | 470 } |
| 458 *currVerb += 1; | 471 *currVerb += 1; |
| 459 lastDirection = nextDirection; | 472 lastDirection = nextDirection; |
| 460 } | 473 } |
| 461 // Success if 4 corners and first point equals last | 474 // Success if 4 corners and first point equals last |
| 462 bool result = 4 == corners && (first == last || autoClose); | 475 bool result = 4 == corners && (first == last || autoClose); |
| 476 if (!result) { |
| 477 // check if we are just an incomplete rectangle, in which case we can |
| 478 // return true, but not claim to be closed. |
| 479 // e.g. |
| 480 // 3 sided rectangle |
| 481 // 4 sided but the last edge is not long enough to reach the start |
| 482 // |
| 483 SkScalar closeX = first.x() - last.x(); |
| 484 SkScalar closeY = first.y() - last.y(); |
| 485 if (closeX && closeY) { |
| 486 return false; // we're diagonal, abort (can we ever reach this?) |
| 487 } |
| 488 int closeDirection = rect_make_dir(closeX, closeY); |
| 489 // make sure the close-segment doesn't double-back on itself |
| 490 if (3 == corners || (4 == corners && closeDirection == lastDirection)) { |
| 491 result = true; |
| 492 autoClose = false; // we are not closed |
| 493 } |
| 494 } |
| 463 if (savePts) { | 495 if (savePts) { |
| 464 *ptsPtr = savePts; | 496 *ptsPtr = savePts; |
| 465 } | 497 } |
| 466 if (result && isClosed) { | 498 if (result && isClosed) { |
| 467 *isClosed = autoClose; | 499 *isClosed = autoClose; |
| 468 } | 500 } |
| 469 if (result && direction) { | 501 if (result && direction) { |
| 470 *direction = firstDirection == ((lastDirection + 1) & 3) ? kCCW_Directio
n : kCW_Direction; | 502 *direction = firstDirection == ((lastDirection + 1) & 3) ? kCCW_Directio
n : kCW_Direction; |
| 471 } | 503 } |
| 472 return result; | 504 return result; |
| (...skipping 2380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2853 switch (this->getFillType()) { | 2885 switch (this->getFillType()) { |
| 2854 case SkPath::kEvenOdd_FillType: | 2886 case SkPath::kEvenOdd_FillType: |
| 2855 case SkPath::kInverseEvenOdd_FillType: | 2887 case SkPath::kInverseEvenOdd_FillType: |
| 2856 w &= 1; | 2888 w &= 1; |
| 2857 break; | 2889 break; |
| 2858 default: | 2890 default: |
| 2859 break; | 2891 break; |
| 2860 } | 2892 } |
| 2861 return SkToBool(w); | 2893 return SkToBool(w); |
| 2862 } | 2894 } |
| OLD | NEW |