1 2 /* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 #include "Test.h" 9 #include "SkPathMeasure.h" 10 11 static void test_small_segment3(skiatest::Reporter* reporter) { 12 #ifdef SK_SCALAR_IS_FLOAT 13 SkPath path; 14 const SkPoint pts[] = { 15 { 0, 0 }, 16 { 100000000000.0f, 100000000000.0f }, { 0, 0 }, { 10, 10 }, 17 { 10, 10 }, { 0, 0 }, { 10, 10 } 18 }; 19 20 path.moveTo(pts[0]); 21 for (size_t i = 1; i < SK_ARRAY_COUNT(pts); i += 3) { 22 path.cubicTo(pts[i], pts[i + 1], pts[i + 2]); 23 } 24 25 SkPathMeasure meas(path, false); 26 meas.getLength(); 27 #endif 28 } 29 30 static void test_small_segment2(skiatest::Reporter* reporter) { 31 #ifdef SK_SCALAR_IS_FLOAT 32 SkPath path; 33 const SkPoint pts[] = { 34 { 0, 0 }, 35 { 100000000000.0f, 100000000000.0f }, { 0, 0 }, 36 { 10, 10 }, { 0, 0 }, 37 }; 38 39 path.moveTo(pts[0]); 40 for (size_t i = 1; i < SK_ARRAY_COUNT(pts); i += 2) { 41 path.quadTo(pts[i], pts[i + 1]); 42 } 43 SkPathMeasure meas(path, false); 44 meas.getLength(); 45 #endif 46 } 47 48 static void test_small_segment(skiatest::Reporter* reporter) { 49 #ifdef SK_SCALAR_IS_FLOAT 50 SkPath path; 51 const SkPoint pts[] = { 52 { 100000, 100000}, 53 // big jump between these points, makes a big segment 54 { SkFloatToScalar(1.0005f), SkFloatToScalar(0.9999f) }, 55 // tiny (non-zero) jump between these points 56 { SK_Scalar1, SK_Scalar1 }, 57 }; 58 59 path.moveTo(pts[0]); 60 for (size_t i = 1; i < SK_ARRAY_COUNT(pts); ++i) { 61 path.lineTo(pts[i]); 62 } 63 SkPathMeasure meas(path, false); 64 65 /* this would assert (before a fix) because we added a segment with 66 the same length as the prev segment, due to the follow (bad) pattern 67 68 d = distance(pts[0], pts[1]); 69 distance += d; 70 seg->fDistance = distance; 71 72 SkASSERT(d > 0); // TRUE 73 SkASSERT(seg->fDistance > prevSeg->fDistance); // FALSE 74 75 This 2nd assert failes because (distance += d) didn't affect distance 76 because distance >>> d. 77 */ 78 meas.getLength(); 79 #endif 80 } 81 82 static void TestPathMeasure(skiatest::Reporter* reporter) { 83 SkPath path; 84 85 path.moveTo(0, 0); 86 path.lineTo(SK_Scalar1, 0); 87 path.lineTo(SK_Scalar1, SK_Scalar1); 88 path.lineTo(0, SK_Scalar1); 89 90 SkPathMeasure meas(path, true); 91 SkScalar length = meas.getLength(); 92 SkASSERT(length == SK_Scalar1*4); 93 94 path.reset(); 95 path.moveTo(0, 0); 96 path.lineTo(SK_Scalar1*3, SK_Scalar1*4); 97 meas.setPath(&path, false); 98 length = meas.getLength(); 99 REPORTER_ASSERT(reporter, length == SK_Scalar1*5); 100 101 path.reset(); 102 path.addCircle(0, 0, SK_Scalar1); 103 meas.setPath(&path, true); 104 length = meas.getLength(); 105 // SkDebugf("circle arc-length = %g\n", length); 106 107 // Test the behavior following a close not followed by a move. 108 path.reset(); 109 path.lineTo(SK_Scalar1, 0); 110 path.lineTo(SK_Scalar1, SK_Scalar1); 111 path.lineTo(0, SK_Scalar1); 112 path.close(); 113 path.lineTo(-SK_Scalar1, 0); 114 meas.setPath(&path, false); 115 length = meas.getLength(); 116 REPORTER_ASSERT(reporter, length == SK_Scalar1 * 4); 117 meas.nextContour(); 118 length = meas.getLength(); 119 REPORTER_ASSERT(reporter, length == SK_Scalar1); 120 SkPoint position; 121 SkVector tangent; 122 REPORTER_ASSERT(reporter, meas.getPosTan(SK_ScalarHalf, &position, &tangent)); 123 REPORTER_ASSERT(reporter, 124 SkScalarNearlyEqual(position.fX, 125 -SK_ScalarHalf, 126 SkFloatToScalar(0.0001f))); 127 REPORTER_ASSERT(reporter, position.fY == 0); 128 REPORTER_ASSERT(reporter, tangent.fX == -SK_Scalar1); 129 REPORTER_ASSERT(reporter, tangent.fY == 0); 130 131 // Test degenerate paths 132 path.reset(); 133 path.moveTo(0, 0); 134 path.lineTo(0, 0); 135 path.lineTo(SK_Scalar1, 0); 136 path.quadTo(SK_Scalar1, 0, SK_Scalar1, 0); 137 path.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1 * 2); 138 path.cubicTo(SK_Scalar1, SK_Scalar1 * 2, 139 SK_Scalar1, SK_Scalar1 * 2, 140 SK_Scalar1, SK_Scalar1 * 2); 141 path.cubicTo(SK_Scalar1*2, SK_Scalar1 * 2, 142 SK_Scalar1*3, SK_Scalar1 * 2, 143 SK_Scalar1*4, SK_Scalar1 * 2); 144 meas.setPath(&path, false); 145 length = meas.getLength(); 146 REPORTER_ASSERT(reporter, length == SK_Scalar1 * 6); 147 REPORTER_ASSERT(reporter, meas.getPosTan(SK_ScalarHalf, &position, &tangent)); 148 REPORTER_ASSERT(reporter, 149 SkScalarNearlyEqual(position.fX, 150 SK_ScalarHalf, 151 SkFloatToScalar(0.0001f))); 152 REPORTER_ASSERT(reporter, position.fY == 0); 153 REPORTER_ASSERT(reporter, tangent.fX == SK_Scalar1); 154 REPORTER_ASSERT(reporter, tangent.fY == 0); 155 REPORTER_ASSERT(reporter, meas.getPosTan(SkFloatToScalar(2.5f), &position, &tangent)); 156 REPORTER_ASSERT(reporter, 157 SkScalarNearlyEqual(position.fX, SK_Scalar1, SkFloatToScalar(0.0001f))); 158 REPORTER_ASSERT(reporter, 159 SkScalarNearlyEqual(position.fY, SkFloatToScalar(1.5f))); 160 REPORTER_ASSERT(reporter, tangent.fX == 0); 161 REPORTER_ASSERT(reporter, tangent.fY == SK_Scalar1); 162 REPORTER_ASSERT(reporter, meas.getPosTan(SkFloatToScalar(4.5f), &position, &tangent)); 163 REPORTER_ASSERT(reporter, 164 SkScalarNearlyEqual(position.fX, 165 SkFloatToScalar(2.5f), 166 SkFloatToScalar(0.0001f))); 167 REPORTER_ASSERT(reporter, 168 SkScalarNearlyEqual(position.fY, 169 SkFloatToScalar(2.0f), 170 SkFloatToScalar(0.0001f))); 171 REPORTER_ASSERT(reporter, tangent.fX == SK_Scalar1); 172 REPORTER_ASSERT(reporter, tangent.fY == 0); 173 174 path.reset(); 175 path.moveTo(0, 0); 176 path.lineTo(SK_Scalar1, 0); 177 path.moveTo(SK_Scalar1, SK_Scalar1); 178 path.moveTo(SK_Scalar1 * 2, SK_Scalar1 * 2); 179 path.lineTo(SK_Scalar1, SK_Scalar1 * 2); 180 meas.setPath(&path, false); 181 length = meas.getLength(); 182 REPORTER_ASSERT(reporter, length == SK_Scalar1); 183 REPORTER_ASSERT(reporter, meas.getPosTan(SK_ScalarHalf, &position, &tangent)); 184 REPORTER_ASSERT(reporter, 185 SkScalarNearlyEqual(position.fX, 186 SK_ScalarHalf, 187 SkFloatToScalar(0.0001f))); 188 REPORTER_ASSERT(reporter, position.fY == 0); 189 REPORTER_ASSERT(reporter, tangent.fX == SK_Scalar1); 190 REPORTER_ASSERT(reporter, tangent.fY == 0); 191 meas.nextContour(); 192 length = meas.getLength(); 193 REPORTER_ASSERT(reporter, length == SK_Scalar1); 194 REPORTER_ASSERT(reporter, meas.getPosTan(SK_ScalarHalf, &position, &tangent)); 195 REPORTER_ASSERT(reporter, 196 SkScalarNearlyEqual(position.fX, 197 SkFloatToScalar(1.5f), 198 SkFloatToScalar(0.0001f))); 199 REPORTER_ASSERT(reporter, 200 SkScalarNearlyEqual(position.fY, 201 SkFloatToScalar(2.0f), 202 SkFloatToScalar(0.0001f))); 203 REPORTER_ASSERT(reporter, tangent.fX == -SK_Scalar1); 204 REPORTER_ASSERT(reporter, tangent.fY == 0); 205 206 test_small_segment(reporter); 207 test_small_segment2(reporter); 208 test_small_segment3(reporter); 209 } 210 211 #include "TestClassDef.h" 212 DEFINE_TESTCLASS("PathMeasure", PathMeasureTestClass, TestPathMeasure) 213