ClipCubicTest.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /*
  2. * Copyright 2011 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/SkBitmap.h"
  8. #include "include/core/SkCanvas.h"
  9. #include "include/core/SkColor.h"
  10. #include "include/core/SkPaint.h"
  11. #include "include/core/SkPath.h"
  12. #include "include/core/SkPoint.h"
  13. #include "include/core/SkRect.h"
  14. #include "include/core/SkRefCnt.h"
  15. #include "include/core/SkScalar.h"
  16. #include "include/core/SkSurface.h"
  17. #include "include/core/SkTypes.h"
  18. #include "include/private/SkFloatBits.h"
  19. #include "src/core/SkCubicClipper.h"
  20. #include "tests/Test.h"
  21. // Currently the supersampler blitter uses int16_t for its index into an array
  22. // the width of the clip. Test that we don't crash/assert if we try to draw
  23. // with a device/clip that is larger.
  24. static void test_giantClip() {
  25. SkBitmap bm;
  26. bm.allocN32Pixels(64919, 1);
  27. SkCanvas canvas(bm);
  28. canvas.clear(SK_ColorTRANSPARENT);
  29. SkPath path;
  30. path.moveTo(0, 0); path.lineTo(1, 0); path.lineTo(33, 1);
  31. SkPaint paint;
  32. paint.setAntiAlias(true);
  33. canvas.drawPath(path, paint);
  34. }
  35. static void PrintCurve(const char *name, const SkPoint crv[4]) {
  36. SkDebugf("%s: %.10g, %.10g, %.10g, %.10g, %.10g, %.10g, %.10g, %.10g\n",
  37. name,
  38. (float)crv[0].fX, (float)crv[0].fY,
  39. (float)crv[1].fX, (float)crv[1].fY,
  40. (float)crv[2].fX, (float)crv[2].fY,
  41. (float)crv[3].fX, (float)crv[3].fY);
  42. }
  43. static bool CurvesAreEqual(const SkPoint c0[4],
  44. const SkPoint c1[4],
  45. float tol) {
  46. for (int i = 0; i < 4; i++) {
  47. if (SkScalarAbs(c0[i].fX - c1[i].fX) > tol ||
  48. SkScalarAbs(c0[i].fY - c1[i].fY) > tol
  49. ) {
  50. PrintCurve("c0", c0);
  51. PrintCurve("c1", c1);
  52. return false;
  53. }
  54. }
  55. return true;
  56. }
  57. static SkPoint* SetCurve(float x0, float y0,
  58. float x1, float y1,
  59. float x2, float y2,
  60. float x3, float y3,
  61. SkPoint crv[4]) {
  62. crv[0].fX = x0; crv[0].fY = y0;
  63. crv[1].fX = x1; crv[1].fY = y1;
  64. crv[2].fX = x2; crv[2].fY = y2;
  65. crv[3].fX = x3; crv[3].fY = y3;
  66. return crv;
  67. }
  68. DEF_TEST(ClipCubic, reporter) {
  69. static SkPoint crv[4] = {
  70. { SkIntToScalar(0), SkIntToScalar(0) },
  71. { SkIntToScalar(2), SkIntToScalar(3) },
  72. { SkIntToScalar(1), SkIntToScalar(10) },
  73. { SkIntToScalar(4), SkIntToScalar(12) }
  74. };
  75. SkCubicClipper clipper;
  76. SkPoint clipped[4], shouldbe[4];
  77. SkIRect clipRect;
  78. bool success;
  79. const float tol = 1e-4f;
  80. // Test no clip, with plenty of room.
  81. clipRect.set(-2, -2, 6, 14);
  82. clipper.setClip(clipRect);
  83. success = clipper.clipCubic(crv, clipped);
  84. REPORTER_ASSERT(reporter, success == true);
  85. REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
  86. 0, 0, 2, 3, 1, 10, 4, 12, shouldbe), tol));
  87. // Test no clip, touching first point.
  88. clipRect.set(-2, 0, 6, 14);
  89. clipper.setClip(clipRect);
  90. success = clipper.clipCubic(crv, clipped);
  91. REPORTER_ASSERT(reporter, success == true);
  92. REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
  93. 0, 0, 2, 3, 1, 10, 4, 12, shouldbe), tol));
  94. // Test no clip, touching last point.
  95. clipRect.set(-2, -2, 6, 12);
  96. clipper.setClip(clipRect);
  97. success = clipper.clipCubic(crv, clipped);
  98. REPORTER_ASSERT(reporter, success == true);
  99. REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
  100. 0, 0, 2, 3, 1, 10, 4, 12, shouldbe), tol));
  101. // Test all clip.
  102. clipRect.set(-2, 14, 6, 20);
  103. clipper.setClip(clipRect);
  104. success = clipper.clipCubic(crv, clipped);
  105. REPORTER_ASSERT(reporter, success == false);
  106. // Test clip at 1.
  107. clipRect.set(-2, 1, 6, 14);
  108. clipper.setClip(clipRect);
  109. success = clipper.clipCubic(crv, clipped);
  110. REPORTER_ASSERT(reporter, success == true);
  111. REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
  112. 0.5126125216f, 1,
  113. 1.841195941f, 4.337081432f,
  114. 1.297019958f, 10.19801331f,
  115. 4, 12,
  116. shouldbe), tol));
  117. // Test clip at 2.
  118. clipRect.set(-2, 2, 6, 14);
  119. clipper.setClip(clipRect);
  120. success = clipper.clipCubic(crv, clipped);
  121. REPORTER_ASSERT(reporter, success == true);
  122. REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
  123. 00.8412352204f, 2,
  124. 1.767683744f, 5.400758266f,
  125. 1.55052948f, 10.36701965f,
  126. 4, 12,
  127. shouldbe), tol));
  128. // Test clip at 11.
  129. clipRect.set(-2, -2, 6, 11);
  130. clipper.setClip(clipRect);
  131. success = clipper.clipCubic(crv, clipped);
  132. REPORTER_ASSERT(reporter, success == true);
  133. REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
  134. 0, 0,
  135. 1.742904663f, 2.614356995f,
  136. 1.207521796f, 8.266430855f,
  137. 3.026495695f, 11,
  138. shouldbe), tol));
  139. // Test clip at 10.
  140. clipRect.set(-2, -2, 6, 10);
  141. clipper.setClip(clipRect);
  142. success = clipper.clipCubic(crv, clipped);
  143. REPORTER_ASSERT(reporter, success == true);
  144. REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
  145. 0, 0,
  146. 1.551193237f, 2.326789856f,
  147. 1.297736168f, 7.059780121f,
  148. 2.505550385f, 10,
  149. shouldbe), tol));
  150. test_giantClip();
  151. }
  152. DEF_TEST(test_fuzz_crbug_698714, reporter) {
  153. auto surface(SkSurface::MakeRasterN32Premul(500, 500));
  154. SkCanvas* canvas = surface->getCanvas();
  155. SkPaint paint;
  156. paint.setAntiAlias(true);
  157. SkPath path;
  158. path.setFillType(SkPath::kWinding_FillType);
  159. path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0,0
  160. path.lineTo(SkBits2Float(0x43434343), SkBits2Float(0x43430143)); //195.263f, 195.005f
  161. path.lineTo(SkBits2Float(0x43434343), SkBits2Float(0x43434343)); //195.263f, 195.263f
  162. path.lineTo(SkBits2Float(0xb5434343), SkBits2Float(0x434300be)); //-7.2741e-07f, 195.003f
  163. // 195.263f, 195.263f, -1.16387e-05f, 3.58641e-38f, 3.85088e-29f,1.86082e-39f
  164. path.cubicTo(SkBits2Float(0x43434343), SkBits2Float(0x43434341),
  165. SkBits2Float(0xb74343bd), SkBits2Float(0x01434343),
  166. SkBits2Float(0x10434343), SkBits2Float(0x00144332));
  167. // 4.11823e-38f, 195.263f, 195.263f, 195.263f, -7.2741e-07f, 195.263f
  168. path.cubicTo(SkBits2Float(0x016037c0), SkBits2Float(0x43434343),
  169. SkBits2Float(0x43434343), SkBits2Float(0x43434343),
  170. SkBits2Float(0xb5434343), SkBits2Float(0x43434343));
  171. // 195.263f, 195.263f, -1.16387e-05f, 3.58641e-38f, 195.263f, -2
  172. path.cubicTo(SkBits2Float(0x43434344), SkBits2Float(0x43434341),
  173. SkBits2Float(0xb74343bd), SkBits2Float(0x01434343),
  174. SkBits2Float(0x43434343), SkBits2Float(0xc0000014));
  175. // -5.87228e+06f, 3.7773e-07f, 3.60231e-13f, -6.64511e+06f,2.77692e-15f, 2.48803e-15f
  176. path.cubicTo(SkBits2Float(0xcab33535), SkBits2Float(0x34cacaca),
  177. SkBits2Float(0x2acacaca), SkBits2Float(0xcacacae3),
  178. SkBits2Float(0x27481927), SkBits2Float(0x27334805));
  179. path.lineTo(SkBits2Float(0xb5434343), SkBits2Float(0x43434343)); //-7.2741e-07f, 195.263f
  180. // 195.263f, 195.263f, -1.16387e-05f, 195.212f, 195.263f, -2
  181. path.cubicTo(SkBits2Float(0x43434343), SkBits2Float(0x43434341),
  182. SkBits2Float(0xb74343b9), SkBits2Float(0x43433643),
  183. SkBits2Float(0x43434343), SkBits2Float(0xc0000014));
  184. path.lineTo(SkBits2Float(0xc7004343), SkBits2Float(0x27480527)); //-32835.3f, 2.77584e-15f
  185. path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0,0
  186. path.close();
  187. canvas->clipRect({0, 0, 65, 202});
  188. canvas->drawPath(path, paint);
  189. }
  190. DEF_TEST(cubic_scan_error_crbug_844457_and_845489, reporter) {
  191. auto surface(SkSurface::MakeRasterN32Premul(100, 100));
  192. SkCanvas* canvas = surface->getCanvas();
  193. SkPaint p;
  194. SkPath path;
  195. path.moveTo(-30/64.0, -31/64.0);
  196. path.cubicTo(-31/64.0, -31/64,-31/64.0, -31/64,-31/64.0, 100);
  197. path.lineTo(100, 100);
  198. canvas->drawPath(path, p);
  199. // May need to define SK_RASTERIZE_EVEN_ROUNDING to trigger the need for this test
  200. path.reset();
  201. path.moveTo(-30/64.0f, -31/64.0f + 1/256.0f);
  202. path.cubicTo(-31/64.0f + 1/256.0f, -31/64.0f + 1/256.0f,
  203. -31/64.0f + 1/256.0f, -31/64.0f + 1/256.0f,
  204. -31/64.0f + 1/256.0f, 100);
  205. path.lineTo(100, 100);
  206. canvas->drawPath(path, p);
  207. }