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