StrokeTest.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /*
  2. * Copyright 2012 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/SkPaint.h"
  8. #include "include/core/SkPath.h"
  9. #include "include/core/SkRect.h"
  10. #include "include/core/SkStrokeRec.h"
  11. #include "src/core/SkStroke.h"
  12. #include "tests/Test.h"
  13. static bool equal(const SkRect& a, const SkRect& b) {
  14. return SkScalarNearlyEqual(a.left(), b.left()) &&
  15. SkScalarNearlyEqual(a.top(), b.top()) &&
  16. SkScalarNearlyEqual(a.right(), b.right()) &&
  17. SkScalarNearlyEqual(a.bottom(), b.bottom());
  18. }
  19. static void test_strokecubic(skiatest::Reporter* reporter) {
  20. uint32_t hexCubicVals[] = {
  21. 0x424c1086, 0x44bcf0cb, // fX=51.0161362 fY=1511.52478
  22. 0x424c107c, 0x44bcf0cb, // fX=51.0160980 fY=1511.52478
  23. 0x424c10c2, 0x44bcf0cb, // fX=51.0163651 fY=1511.52478
  24. 0x424c1119, 0x44bcf0ca, // fX=51.0166969 fY=1511.52466
  25. };
  26. SkPoint cubicVals[] = {
  27. {51.0161362f, 1511.52478f },
  28. {51.0160980f, 1511.52478f },
  29. {51.0163651f, 1511.52478f },
  30. {51.0166969f, 1511.52466f },
  31. };
  32. SkPaint paint;
  33. paint.setStyle(SkPaint::kStroke_Style);
  34. paint.setStrokeWidth(0.394537568f);
  35. SkPath path, fillPath;
  36. path.moveTo(cubicVals[0]);
  37. path.cubicTo(cubicVals[1], cubicVals[2], cubicVals[3]);
  38. paint.getFillPath(path, &fillPath);
  39. path.reset();
  40. path.moveTo(SkBits2Float(hexCubicVals[0]), SkBits2Float(hexCubicVals[1]));
  41. path.cubicTo(SkBits2Float(hexCubicVals[2]), SkBits2Float(hexCubicVals[3]),
  42. SkBits2Float(hexCubicVals[4]), SkBits2Float(hexCubicVals[5]),
  43. SkBits2Float(hexCubicVals[6]), SkBits2Float(hexCubicVals[7]));
  44. paint.getFillPath(path, &fillPath);
  45. }
  46. static void test_strokerect(skiatest::Reporter* reporter) {
  47. const SkScalar width = SkIntToScalar(10);
  48. SkPaint paint;
  49. paint.setStyle(SkPaint::kStroke_Style);
  50. paint.setStrokeWidth(width);
  51. SkRect r = { 0, 0, SkIntToScalar(200), SkIntToScalar(100) };
  52. SkRect outer(r);
  53. outer.outset(width/2, width/2);
  54. static const SkPaint::Join joins[] = {
  55. SkPaint::kMiter_Join, SkPaint::kRound_Join, SkPaint::kBevel_Join
  56. };
  57. for (size_t i = 0; i < SK_ARRAY_COUNT(joins); ++i) {
  58. paint.setStrokeJoin(joins[i]);
  59. SkPath path, fillPath;
  60. path.addRect(r);
  61. paint.getFillPath(path, &fillPath);
  62. REPORTER_ASSERT(reporter, equal(outer, fillPath.getBounds()));
  63. bool isMiter = SkPaint::kMiter_Join == joins[i];
  64. SkRect nested[2];
  65. REPORTER_ASSERT(reporter, fillPath.isNestedFillRects(nested) == isMiter);
  66. if (isMiter) {
  67. SkRect inner(r);
  68. inner.inset(width/2, width/2);
  69. REPORTER_ASSERT(reporter, equal(nested[0], outer));
  70. REPORTER_ASSERT(reporter, equal(nested[1], inner));
  71. }
  72. }
  73. }
  74. static void test_strokerec_equality(skiatest::Reporter* reporter) {
  75. {
  76. SkStrokeRec s1(SkStrokeRec::kFill_InitStyle);
  77. SkStrokeRec s2(SkStrokeRec::kFill_InitStyle);
  78. REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
  79. // Test that style mismatch is detected.
  80. s2.setHairlineStyle();
  81. REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
  82. s1.setHairlineStyle();
  83. REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
  84. // ResScale is not part of equality.
  85. s1.setResScale(2.1f);
  86. s2.setResScale(1.2f);
  87. REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
  88. s1.setFillStyle();
  89. s2.setFillStyle();
  90. REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
  91. s1.setStrokeStyle(1.0f, false);
  92. s2.setStrokeStyle(1.0f, false);
  93. s1.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.9f);
  94. s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.9f);
  95. REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
  96. }
  97. // Stroke parameters on fill or hairline style are not part of equality.
  98. {
  99. SkStrokeRec s1(SkStrokeRec::kFill_InitStyle);
  100. SkStrokeRec s2(SkStrokeRec::kFill_InitStyle);
  101. for (int i = 0; i < 2; ++i) {
  102. s1.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.9f);
  103. s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.1f);
  104. REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
  105. s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kBevel_Join, 2.9f);
  106. REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
  107. s2.setStrokeParams(SkPaint::kRound_Cap, SkPaint::kRound_Join, 2.9f);
  108. REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
  109. s1.setHairlineStyle();
  110. s2.setHairlineStyle();
  111. }
  112. }
  113. // Stroke parameters on stroke style are part of equality.
  114. {
  115. SkStrokeRec s1(SkStrokeRec::kFill_InitStyle);
  116. SkStrokeRec s2(SkStrokeRec::kFill_InitStyle);
  117. s1.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.9f);
  118. s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.9f);
  119. s1.setStrokeStyle(1.0f, false);
  120. s2.setStrokeStyle(1.0f, true);
  121. REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
  122. s2.setStrokeStyle(2.1f, false);
  123. REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
  124. s2.setStrokeStyle(1.0f, false);
  125. REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
  126. s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.1f);
  127. REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
  128. s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kBevel_Join, 2.9f);
  129. REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
  130. s2.setStrokeParams(SkPaint::kRound_Cap, SkPaint::kRound_Join, 2.9f);
  131. REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
  132. // Sets fill.
  133. s1.setStrokeStyle(0.0f, true);
  134. s2.setStrokeStyle(0.0f, true);
  135. REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
  136. }
  137. }
  138. // From skbug.com/6491. The large stroke width can cause numerical instabilities.
  139. static void test_big_stroke(skiatest::Reporter* reporter) {
  140. SkPaint paint;
  141. paint.setStyle(SkPaint::kStrokeAndFill_Style);
  142. paint.setStrokeWidth(1.49679073e+10f);
  143. SkPath path;
  144. path.setFillType(SkPath::kWinding_FillType);
  145. path.moveTo(SkBits2Float(0x46380000), SkBits2Float(0xc6380000)); // 11776, -11776
  146. path.lineTo(SkBits2Float(0x46a00000), SkBits2Float(0xc6a00000)); // 20480, -20480
  147. path.lineTo(SkBits2Float(0x468c0000), SkBits2Float(0xc68c0000)); // 17920, -17920
  148. path.lineTo(SkBits2Float(0x46100000), SkBits2Float(0xc6100000)); // 9216, -9216
  149. path.lineTo(SkBits2Float(0x46380000), SkBits2Float(0xc6380000)); // 11776, -11776
  150. path.close();
  151. SkPath strokeAndFillPath;
  152. paint.getFillPath(path, &strokeAndFillPath);
  153. }
  154. DEF_TEST(Stroke, reporter) {
  155. test_strokecubic(reporter);
  156. test_strokerect(reporter);
  157. test_strokerec_equality(reporter);
  158. test_big_stroke(reporter);
  159. }