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