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 
test_small_segment3()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 
test_small_segment2()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 
test_small_segment()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 
DEF_TEST(PathMeasure,reporter)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 
DEF_TEST(PathMeasureConic,reporter)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