PathOpsTightBoundsTest.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /*
  2. * Copyright 2013 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. #include "include/core/SkCanvas.h"
  8. #include "include/utils/SkRandom.h"
  9. #include "src/core/SkTSort.h"
  10. #include "tests/PathOpsExtendedTest.h"
  11. #include "tests/PathOpsThreadedCommon.h"
  12. #include "tests/Test.h"
  13. static void testTightBoundsLines(PathOpsThreadState* data) {
  14. SkRandom ran;
  15. for (int index = 0; index < 1000; ++index) {
  16. SkPath path;
  17. int contourCount = ran.nextRangeU(1, 10);
  18. for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
  19. int lineCount = ran.nextRangeU(1, 10);
  20. path.moveTo(ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000));
  21. for (int lIndex = 0; lIndex < lineCount; ++lIndex) {
  22. path.lineTo(ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000));
  23. }
  24. if (ran.nextBool()) {
  25. path.close();
  26. }
  27. }
  28. SkRect classicBounds = path.getBounds();
  29. SkRect tightBounds;
  30. REPORTER_ASSERT(data->fReporter, TightBounds(path, &tightBounds));
  31. REPORTER_ASSERT(data->fReporter, classicBounds == tightBounds);
  32. }
  33. }
  34. DEF_TEST(PathOpsTightBoundsLines, reporter) {
  35. initializeTests(reporter, "tightBoundsLines");
  36. PathOpsThreadedTestRunner testRunner(reporter);
  37. int outerCount = reporter->allowExtendedTest() ? 100 : 1;
  38. for (int index = 0; index < outerCount; ++index) {
  39. for (int idx2 = 0; idx2 < 10; ++idx2) {
  40. *testRunner.fRunnables.append() =
  41. new PathOpsThreadedRunnable(&testTightBoundsLines, 0, 0, 0, 0, &testRunner);
  42. }
  43. }
  44. testRunner.render();
  45. }
  46. static void testTightBoundsQuads(PathOpsThreadState* data) {
  47. SkRandom ran;
  48. const int bitWidth = 32;
  49. const int bitHeight = 32;
  50. const float pathMin = 1;
  51. const float pathMax = (float) (bitHeight - 2);
  52. SkBitmap& bits = *data->fBitmap;
  53. if (bits.width() == 0) {
  54. bits.allocN32Pixels(bitWidth, bitHeight);
  55. }
  56. SkCanvas canvas(bits);
  57. SkPaint paint;
  58. for (int index = 0; index < 100; ++index) {
  59. SkPath path;
  60. int contourCount = ran.nextRangeU(1, 10);
  61. for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
  62. int lineCount = ran.nextRangeU(1, 10);
  63. path.moveTo(ran.nextRangeF(1, pathMax), ran.nextRangeF(pathMin, pathMax));
  64. for (int lIndex = 0; lIndex < lineCount; ++lIndex) {
  65. if (ran.nextBool()) {
  66. path.lineTo(ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax));
  67. } else {
  68. path.quadTo(ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax),
  69. ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax));
  70. }
  71. }
  72. if (ran.nextBool()) {
  73. path.close();
  74. }
  75. }
  76. SkRect classicBounds = path.getBounds();
  77. SkRect tightBounds;
  78. REPORTER_ASSERT(data->fReporter, TightBounds(path, &tightBounds));
  79. REPORTER_ASSERT(data->fReporter, classicBounds.contains(tightBounds));
  80. canvas.drawColor(SK_ColorWHITE);
  81. canvas.drawPath(path, paint);
  82. SkIRect bitsWritten = {31, 31, 0, 0};
  83. for (int y = 0; y < bitHeight; ++y) {
  84. uint32_t* addr1 = data->fBitmap->getAddr32(0, y);
  85. bool lineWritten = false;
  86. for (int x = 0; x < bitWidth; ++x) {
  87. if (addr1[x] == (uint32_t) -1) {
  88. continue;
  89. }
  90. lineWritten = true;
  91. bitsWritten.fLeft = SkTMin(bitsWritten.fLeft, x);
  92. bitsWritten.fRight = SkTMax(bitsWritten.fRight, x);
  93. }
  94. if (!lineWritten) {
  95. continue;
  96. }
  97. bitsWritten.fTop = SkTMin(bitsWritten.fTop, y);
  98. bitsWritten.fBottom = SkTMax(bitsWritten.fBottom, y);
  99. }
  100. if (!bitsWritten.isEmpty()) {
  101. SkIRect tightOut;
  102. tightBounds.roundOut(&tightOut);
  103. REPORTER_ASSERT(data->fReporter, tightOut.contains(bitsWritten));
  104. }
  105. }
  106. }
  107. DEF_TEST(PathOpsTightBoundsQuads, reporter) {
  108. initializeTests(reporter, "tightBoundsQuads");
  109. PathOpsThreadedTestRunner testRunner(reporter);
  110. int outerCount = reporter->allowExtendedTest() ? 100 : 1;
  111. for (int index = 0; index < outerCount; ++index) {
  112. for (int idx2 = 0; idx2 < 10; ++idx2) {
  113. *testRunner.fRunnables.append() =
  114. new PathOpsThreadedRunnable(&testTightBoundsQuads, 0, 0, 0, 0, &testRunner);
  115. }
  116. }
  117. testRunner.render();
  118. }
  119. DEF_TEST(PathOpsTightBoundsMove, reporter) {
  120. SkPath path;
  121. path.moveTo(10, 10);
  122. path.close();
  123. path.moveTo(20, 20);
  124. path.lineTo(20, 20);
  125. path.close();
  126. path.moveTo(15, 15);
  127. path.lineTo(15, 15);
  128. path.close();
  129. const SkRect& bounds = path.getBounds();
  130. SkRect tight;
  131. REPORTER_ASSERT(reporter, TightBounds(path, &tight));
  132. REPORTER_ASSERT(reporter, bounds == tight);
  133. }
  134. DEF_TEST(PathOpsTightBoundsMoveOne, reporter) {
  135. SkPath path;
  136. path.moveTo(20, 20);
  137. const SkRect& bounds = path.getBounds();
  138. SkRect tight;
  139. REPORTER_ASSERT(reporter, TightBounds(path, &tight));
  140. REPORTER_ASSERT(reporter, bounds == tight);
  141. }
  142. DEF_TEST(PathOpsTightBoundsMoveTwo, reporter) {
  143. SkPath path;
  144. path.moveTo(20, 20);
  145. path.moveTo(40, 40);
  146. const SkRect& bounds = path.getBounds();
  147. SkRect tight;
  148. REPORTER_ASSERT(reporter, TightBounds(path, &tight));
  149. REPORTER_ASSERT(reporter, bounds == tight);
  150. }
  151. DEF_TEST(PathOpsTightBoundsTiny, reporter) {
  152. SkPath path;
  153. path.moveTo(1, 1);
  154. path.quadTo(1.000001f, 1, 1, 1);
  155. const SkRect& bounds = path.getBounds();
  156. SkRect tight;
  157. REPORTER_ASSERT(reporter, TightBounds(path, &tight));
  158. SkRect moveBounds = {1, 1, 1, 1};
  159. REPORTER_ASSERT(reporter, bounds != tight);
  160. REPORTER_ASSERT(reporter, moveBounds == tight);
  161. }
  162. DEF_TEST(PathOpsTightBoundsWellBehaved, reporter) {
  163. SkPath path;
  164. path.moveTo(1, 1);
  165. path.quadTo(2, 3, 4, 5);
  166. const SkRect& bounds = path.getBounds();
  167. SkRect tight;
  168. REPORTER_ASSERT(reporter, TightBounds(path, &tight));
  169. REPORTER_ASSERT(reporter, bounds == tight);
  170. }
  171. DEF_TEST(PathOpsTightBoundsIllBehaved, reporter) {
  172. SkPath path;
  173. path.moveTo(1, 1);
  174. path.quadTo(4, 3, 2, 2);
  175. const SkRect& bounds = path.getBounds();
  176. SkRect tight;
  177. REPORTER_ASSERT(reporter, TightBounds(path, &tight));
  178. REPORTER_ASSERT(reporter, bounds != tight);
  179. }
  180. DEF_TEST(PathOpsTightBoundsIllBehavedScaled, reporter) {
  181. SkPath path;
  182. path.moveTo(0, 0);
  183. path.quadTo(1048578, 1048577, 1048576, 1048576);
  184. const SkRect& bounds = path.getBounds();
  185. SkRect tight;
  186. REPORTER_ASSERT(reporter, TightBounds(path, &tight));
  187. REPORTER_ASSERT(reporter, bounds != tight);
  188. REPORTER_ASSERT(reporter, tight.right() == 1048576);
  189. REPORTER_ASSERT(reporter, tight.bottom() == 1048576);
  190. }