Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Functions
PathMeasureTest.cpp File Reference
#include "include/core/SkContourMeasure.h"
#include "include/core/SkPath.h"
#include "include/core/SkPathMeasure.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
#include "src/core/SkPathMeasurePriv.h"
#include "src/core/SkPathPriv.h"
#include "tests/Test.h"
#include <array>
#include <cstddef>
#include <initializer_list>
#include <utility>

Go to the source code of this file.

Functions

static void test_small_segment3 (skiatest::Reporter *reporter)
 
static void test_small_segment2 ()
 
static void test_small_segment ()
 
 DEF_TEST (PathMeasure, reporter)
 
 DEF_TEST (PathMeasureConic, reporter)
 
 DEF_TEST (PathMeasure_nextctr, reporter)
 
static void test_90_degrees (const sk_sp< SkContourMeasure > &cm, SkScalar radius, skiatest::Reporter *reporter)
 
static void test_empty_contours (skiatest::Reporter *reporter)
 
static void test_MLM_contours (skiatest::Reporter *reporter)
 
static void test_shrink (skiatest::Reporter *reporter)
 
 DEF_TEST (contour_measure, reporter)
 

Function Documentation

◆ DEF_TEST() [1/4]

DEF_TEST ( contour_measure  ,
reporter   
)

Definition at line 330 of file PathMeasureTest.cpp.

330 {
331 SkPath path;
332 path.addCircle(0, 0, 100);
333 path.addCircle(0, 0, 10);
334
335 SkContourMeasureIter fact(path, false);
336 path.reset(); // we should not need the path avert we created the factory
337
338 auto cm0 = fact.next();
339 auto cm1 = fact.next();
340
341 REPORTER_ASSERT(reporter, cm0->isClosed());
342 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(cm0->length(), 200 * SK_ScalarPI, 1.5f));
343
344 test_90_degrees(cm0, 100, reporter);
345
346 REPORTER_ASSERT(reporter, cm1->isClosed());
347 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(cm1->length(), 20 * SK_ScalarPI, 0.5f));
348
349 test_90_degrees(cm1, 10, reporter);
350
351 auto cm2 = fact.next();
353
356
358}
reporter
static void test_empty_contours(skiatest::Reporter *reporter)
static void test_shrink(skiatest::Reporter *reporter)
static void test_90_degrees(const sk_sp< SkContourMeasure > &cm, SkScalar radius, skiatest::Reporter *reporter)
static void test_MLM_contours(skiatest::Reporter *reporter)
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
Definition SkScalar.h:107
#define SK_ScalarPI
Definition SkScalar.h:21
#define REPORTER_ASSERT(r, cond,...)
Definition Test.h:286
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition switches.h:57

◆ DEF_TEST() [2/4]

DEF_TEST ( PathMeasure  ,
reporter   
)

Definition at line 104 of file PathMeasureTest.cpp.

104 {
105 SkPath path;
106
107 path.moveTo(0, 0);
108 path.lineTo(SK_Scalar1, 0);
109 path.lineTo(SK_Scalar1, SK_Scalar1);
110 path.lineTo(0, SK_Scalar1);
111
112 SkPathMeasure meas(path, true);
113 SkScalar length = meas.getLength();
115
116 path.reset();
117 path.moveTo(0, 0);
118 path.lineTo(SK_Scalar1*3, SK_Scalar1*4);
119 meas.setPath(&path, false);
120 length = meas.getLength();
122
123 path.reset();
124 path.addCircle(0, 0, SK_Scalar1);
125 meas.setPath(&path, true);
126 length = meas.getLength();
127// SkDebugf("circle arc-length = %g\n", length);
128
129 // Test the behavior following a close not followed by a move.
130 path.reset();
131 path.lineTo(SK_Scalar1, 0);
132 path.lineTo(SK_Scalar1, SK_Scalar1);
133 path.lineTo(0, SK_Scalar1);
134 path.close();
135 path.lineTo(-SK_Scalar1, 0);
136 meas.setPath(&path, false);
137 length = meas.getLength();
139 meas.nextContour();
140 length = meas.getLength();
142 SkPoint position;
143 SkVector tangent;
144 REPORTER_ASSERT(reporter, meas.getPosTan(SK_ScalarHalf, &position, &tangent));
146 SkScalarNearlyEqual(position.fX,
148 0.0001f));
149 REPORTER_ASSERT(reporter, position.fY == 0);
151 REPORTER_ASSERT(reporter, tangent.fY == 0);
152
153 // Test degenerate paths
154 path.reset();
155 path.moveTo(0, 0);
156 path.lineTo(0, 0);
157 path.lineTo(SK_Scalar1, 0);
158 path.quadTo(SK_Scalar1, 0, SK_Scalar1, 0);
160 path.cubicTo(SK_Scalar1, SK_Scalar1 * 2,
163 path.cubicTo(SK_Scalar1*2, SK_Scalar1 * 2,
164 SK_Scalar1*3, SK_Scalar1 * 2,
165 SK_Scalar1*4, SK_Scalar1 * 2);
166 meas.setPath(&path, false);
167 length = meas.getLength();
169 REPORTER_ASSERT(reporter, meas.getPosTan(SK_ScalarHalf, &position, &tangent));
171 SkScalarNearlyEqual(position.fX,
173 0.0001f));
174 REPORTER_ASSERT(reporter, position.fY == 0);
176 REPORTER_ASSERT(reporter, tangent.fY == 0);
177 REPORTER_ASSERT(reporter, meas.getPosTan(2.5f, &position, &tangent));
179 SkScalarNearlyEqual(position.fX, SK_Scalar1, 0.0001f));
181 SkScalarNearlyEqual(position.fY, 1.5f));
182 REPORTER_ASSERT(reporter, tangent.fX == 0);
184 REPORTER_ASSERT(reporter, meas.getPosTan(4.5f, &position, &tangent));
186 SkScalarNearlyEqual(position.fX,
187 2.5f,
188 0.0001f));
190 SkScalarNearlyEqual(position.fY,
191 2.0f,
192 0.0001f));
194 REPORTER_ASSERT(reporter, tangent.fY == 0);
195
196 path.reset();
197 path.moveTo(0, 0);
198 path.lineTo(SK_Scalar1, 0);
199 path.moveTo(SK_Scalar1, SK_Scalar1);
200 path.moveTo(SK_Scalar1 * 2, SK_Scalar1 * 2);
201 path.lineTo(SK_Scalar1, SK_Scalar1 * 2);
202 meas.setPath(&path, false);
203 length = meas.getLength();
205 REPORTER_ASSERT(reporter, meas.getPosTan(SK_ScalarHalf, &position, &tangent));
207 SkScalarNearlyEqual(position.fX,
209 0.0001f));
210 REPORTER_ASSERT(reporter, position.fY == 0);
212 REPORTER_ASSERT(reporter, tangent.fY == 0);
213 meas.nextContour();
214 length = meas.getLength();
216 REPORTER_ASSERT(reporter, meas.getPosTan(SK_ScalarHalf, &position, &tangent));
218 SkScalarNearlyEqual(position.fX,
219 1.5f,
220 0.0001f));
222 SkScalarNearlyEqual(position.fY,
223 2.0f,
224 0.0001f));
226 REPORTER_ASSERT(reporter, tangent.fY == 0);
227
231
232 // SkPathMeasure isn't copyable, but it should be move-able
233 SkPathMeasure meas2(std::move(meas));
234 meas = std::move(meas2);
235}
static void test_small_segment3(skiatest::Reporter *reporter)
static void test_small_segment2()
static void test_small_segment()
#define SkASSERT(cond)
Definition SkAssert.h:116
#define SK_Scalar1
Definition SkScalar.h:18
#define SK_ScalarHalf
Definition SkScalar.h:19
float SkScalar
Definition extension.cpp:12
size_t length
float fX
x-axis value
float fY
y-axis value

◆ DEF_TEST() [3/4]

DEF_TEST ( PathMeasure_nextctr  ,
reporter   
)

Definition at line 254 of file PathMeasureTest.cpp.

254 {
255 SkPath path;
256 path.moveTo(0, 0); path.lineTo(100, 0);
257
258 SkPathMeasure meas(path, false);
259 // only expect 1 contour, even if we didn't explicitly call getLength() ourselves
260 REPORTER_ASSERT(reporter, !meas.nextContour());
261}

◆ DEF_TEST() [4/4]

DEF_TEST ( PathMeasureConic  ,
reporter   
)

Definition at line 237 of file PathMeasureTest.cpp.

237 {
238 SkPoint stdP, hiP, pts[] = {{0,0}, {100,0}, {100,0}};
239 SkPath p;
240 p.moveTo(0, 0);
241 p.conicTo(pts[1], pts[2], 1);
242 SkPathMeasure stdm(p, false);
243 REPORTER_ASSERT(reporter, stdm.getPosTan(20, &stdP, nullptr));
244 p.reset();
245 p.moveTo(0, 0);
246 p.conicTo(pts[1], pts[2], 10);
247 stdm.setPath(&p, false);
248 REPORTER_ASSERT(reporter, stdm.getPosTan(20, &hiP, nullptr));
249 REPORTER_ASSERT(reporter, 19.5f < stdP.fX && stdP.fX < 20.5f);
250 REPORTER_ASSERT(reporter, 19.5f < hiP.fX && hiP.fX < 20.5f);
251}

◆ test_90_degrees()

static void test_90_degrees ( const sk_sp< SkContourMeasure > &  cm,
SkScalar  radius,
skiatest::Reporter reporter 
)
static

Definition at line 263 of file PathMeasureTest.cpp.

264 {
265 SkPoint pos;
266 SkVector tan;
267 SkScalar distance = cm->length() / 4;
268 bool success = cm->getPosTan(distance, &pos, &tan);
269
270 REPORTER_ASSERT(reporter, success);
275}
SkPoint pos
bool getPosTan(SkScalar distance, SkPoint *position, SkVector *tangent) const
SkScalar length() const

◆ test_empty_contours()

static void test_empty_contours ( skiatest::Reporter reporter)
static

Definition at line 277 of file PathMeasureTest.cpp.

277 {
278 SkPath path;
279
280 path.moveTo(0, 0).lineTo(100, 100).lineTo(200, 100);
281 path.moveTo(2, 2).moveTo(3, 3); // zero-length(s)
282 path.moveTo(4, 4).close().close().close(); // zero-length
283 path.moveTo(5, 5).lineTo(5, 5); // zero-length
284 path.moveTo(5, 5).lineTo(5, 5).close(); // zero-length
285 path.moveTo(5, 5).lineTo(5, 5).close().close(); // zero-length
286 path.moveTo(6, 6).lineTo(7, 7);
287 path.moveTo(10, 10); // zero-length
288
289 SkContourMeasureIter fact(path, false);
290
291 // given the above construction, we expect only 2 contours (the rest are "empty")
292
293 REPORTER_ASSERT(reporter, fact.next());
294 REPORTER_ASSERT(reporter, fact.next());
295 REPORTER_ASSERT(reporter, !fact.next());
296}

◆ test_MLM_contours()

static void test_MLM_contours ( skiatest::Reporter reporter)
static

Definition at line 298 of file PathMeasureTest.cpp.

298 {
299 SkPath path;
300
301 // This odd sequence (with a trailing moveTo) used to return a 2nd contour, which is
302 // wrong, since the contract for a measure is to only return non-zero length contours.
303 path.moveTo(10, 10).lineTo(20, 20).moveTo(30, 30);
304
305 for (bool forceClosed : {false, true}) {
306 SkContourMeasureIter fact(path, forceClosed);
307 REPORTER_ASSERT(reporter, fact.next());
308 REPORTER_ASSERT(reporter, !fact.next());
309 }
310}

◆ test_shrink()

static void test_shrink ( skiatest::Reporter reporter)
static

Definition at line 312 of file PathMeasureTest.cpp.

312 {
313 SkPath path;
314 path.addRect({1, 2, 3, 4});
315 path.incReserve(100); // give shrinkToFit() something to do
316
317 SkContourMeasureIter iter(path, false);
318
319 // shrinks the allocation, possibly relocating the underlying arrays.
320 // The contouremasureiter needs to have safely copied path, to be unaffected by this
321 // change to "path".
323
324 // Note, this failed (before the fix) on an ASAN build, which notices that we were
325 // using an internal iterator of the passed-in path, not our copy.
326 while (iter.next())
327 ;
328}
static void ShrinkToFit(SkPath *path)
Definition SkPathPriv.h:130

◆ test_small_segment()

static void test_small_segment ( )
static

Definition at line 72 of file PathMeasureTest.cpp.

72 {
74 const SkPoint pts[] = {
75 { 100000, 100000},
76 // big jump between these points, makes a big segment
77 { 1.0005f, 0.9999f },
78 // tiny (non-zero) jump between these points
80 };
81
82 path.moveTo(pts[0]);
83 for (size_t i = 1; i < std::size(pts); ++i) {
84 path.lineTo(pts[i]);
85 }
86 SkPathMeasure meas(path, false);
87
88 /* this would assert (before a fix) because we added a segment with
89 the same length as the prev segment, due to the follow (bad) pattern
90
91 d = distance(pts[0], pts[1]);
92 distance += d;
93 seg->fDistance = distance;
94
95 SkASSERT(d > 0); // TRUE
96 SkASSERT(seg->fDistance > prevSeg->fDistance); // FALSE
97
98 This 2nd assert failes because (distance += d) didn't affect distance
99 because distance >>> d.
100 */
101 meas.getLength();
102}

◆ test_small_segment2()

static void test_small_segment2 ( )
static

Definition at line 56 of file PathMeasureTest.cpp.

56 {
58 const SkPoint pts[] = {
59 { 0, 0 },
60 { 100000000000.0f, 100000000000.0f }, { 0, 0 },
61 { 10, 10 }, { 0, 0 },
62 };
63
64 path.moveTo(pts[0]);
65 for (size_t i = 1; i < std::size(pts); i += 2) {
66 path.quadTo(pts[i], pts[i + 1]);
67 }
68 SkPathMeasure meas(path, false);
69 meas.getLength();
70}

◆ test_small_segment3()

static void test_small_segment3 ( skiatest::Reporter reporter)
static

Definition at line 24 of file PathMeasureTest.cpp.

24 {
26 const SkPoint pts[] = {
27 { 0, 0 },
28 { 100000000000.0f, 100000000000.0f }, { 0, 0 }, { 10, 10 },
29 { 10, 10 }, { 0, 0 }, { 10, 10 }
30 };
31
32 path.moveTo(pts[0]);
33 for (size_t i = 1; i < std::size(pts); i += 3) {
34 path.cubicTo(pts[i], pts[i + 1], pts[i + 2]);
35 }
36
37 SkPathMeasure meas(path, false);
38 meas.getLength();
39
40 // Now check that we cap the segment size even with very large resolution scales.
41 // Earlier versions allowed the pathmeasure to recurse without limit in the face
42 // of a very large scale.
43 //
44 // Before this limit, the above meas had 15K segments, and when built with
45 // a resScale of 100, it had 184K segments -- for 1 cubic!
46 {
48 REPORTER_ASSERT(reporter, n < 300);
49
50 constexpr float resScale = 1000;
51 n = SkPathMeasurePriv::CountSegments(SkPathMeasure(path, false, resScale));
52 REPORTER_ASSERT(reporter, n < 300);
53 }
54}
static size_t CountSegments(const SkPathMeasure &)