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 |