SkQuadClipper.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /*
  2. * Copyright 2009 The Android Open Source Project
  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. #include "src/core/SkGeometry.h"
  8. #include "src/core/SkQuadClipper.h"
  9. #include <utility>
  10. SkQuadClipper::SkQuadClipper() {
  11. fClip.setEmpty();
  12. }
  13. void SkQuadClipper::setClip(const SkIRect& clip) {
  14. // conver to scalars, since that's where we'll see the points
  15. fClip.set(clip);
  16. }
  17. ///////////////////////////////////////////////////////////////////////////////
  18. static bool chopMonoQuadAt(SkScalar c0, SkScalar c1, SkScalar c2,
  19. SkScalar target, SkScalar* t) {
  20. /* Solve F(t) = y where F(t) := [0](1-t)^2 + 2[1]t(1-t) + [2]t^2
  21. * We solve for t, using quadratic equation, hence we have to rearrange
  22. * our cooefficents to look like At^2 + Bt + C
  23. */
  24. SkScalar A = c0 - c1 - c1 + c2;
  25. SkScalar B = 2*(c1 - c0);
  26. SkScalar C = c0 - target;
  27. SkScalar roots[2]; // we only expect one, but make room for 2 for safety
  28. int count = SkFindUnitQuadRoots(A, B, C, roots);
  29. if (count) {
  30. *t = roots[0];
  31. return true;
  32. }
  33. return false;
  34. }
  35. static bool chopMonoQuadAtY(SkPoint pts[3], SkScalar y, SkScalar* t) {
  36. return chopMonoQuadAt(pts[0].fY, pts[1].fY, pts[2].fY, y, t);
  37. }
  38. ///////////////////////////////////////////////////////////////////////////////
  39. /* If we somehow returned the fact that we had to flip the pts in Y, we could
  40. communicate that to setQuadratic, and then avoid having to flip it back
  41. here (only to have setQuadratic do the flip again)
  42. */
  43. bool SkQuadClipper::clipQuad(const SkPoint srcPts[3], SkPoint dst[3]) {
  44. bool reverse;
  45. // we need the data to be monotonically increasing in Y
  46. if (srcPts[0].fY > srcPts[2].fY) {
  47. dst[0] = srcPts[2];
  48. dst[1] = srcPts[1];
  49. dst[2] = srcPts[0];
  50. reverse = true;
  51. } else {
  52. memcpy(dst, srcPts, 3 * sizeof(SkPoint));
  53. reverse = false;
  54. }
  55. // are we completely above or below
  56. const SkScalar ctop = fClip.fTop;
  57. const SkScalar cbot = fClip.fBottom;
  58. if (dst[2].fY <= ctop || dst[0].fY >= cbot) {
  59. return false;
  60. }
  61. SkScalar t;
  62. SkPoint tmp[5]; // for SkChopQuadAt
  63. // are we partially above
  64. if (dst[0].fY < ctop) {
  65. if (chopMonoQuadAtY(dst, ctop, &t)) {
  66. // take the 2nd chopped quad
  67. SkChopQuadAt(dst, tmp, t);
  68. dst[0] = tmp[2];
  69. dst[1] = tmp[3];
  70. } else {
  71. // if chopMonoQuadAtY failed, then we may have hit inexact numerics
  72. // so we just clamp against the top
  73. for (int i = 0; i < 3; i++) {
  74. if (dst[i].fY < ctop) {
  75. dst[i].fY = ctop;
  76. }
  77. }
  78. }
  79. }
  80. // are we partially below
  81. if (dst[2].fY > cbot) {
  82. if (chopMonoQuadAtY(dst, cbot, &t)) {
  83. SkChopQuadAt(dst, tmp, t);
  84. dst[1] = tmp[1];
  85. dst[2] = tmp[2];
  86. } else {
  87. // if chopMonoQuadAtY failed, then we may have hit inexact numerics
  88. // so we just clamp against the bottom
  89. for (int i = 0; i < 3; i++) {
  90. if (dst[i].fY > cbot) {
  91. dst[i].fY = cbot;
  92. }
  93. }
  94. }
  95. }
  96. if (reverse) {
  97. using std::swap;
  98. swap(dst[0], dst[2]);
  99. }
  100. return true;
  101. }