1 /*
2  * Copyright 2013 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 #include "SkPath.h"
8 #include "SkPathOps.h"
9 #include "SkPoint.h"
10 #include "Test.h"
11 
12 static const SkPoint nonFinitePts[] = {
13     { SK_ScalarInfinity, 0 },
14     { 0, SK_ScalarInfinity },
15     { SK_ScalarInfinity, SK_ScalarInfinity },
16     { SK_ScalarNegativeInfinity, 0},
17     { 0, SK_ScalarNegativeInfinity },
18     { SK_ScalarNegativeInfinity, SK_ScalarNegativeInfinity },
19     { SK_ScalarNegativeInfinity, SK_ScalarInfinity },
20     { SK_ScalarInfinity, SK_ScalarNegativeInfinity },
21     { SK_ScalarNaN, 0 },
22     { 0, SK_ScalarNaN },
23     { SK_ScalarNaN, SK_ScalarNaN },
24 };
25 
26 const size_t nonFinitePtsCount = sizeof(nonFinitePts) / sizeof(nonFinitePts[0]);
27 
28 static const SkPoint finitePts[] = {
29     { 0, 0 },
30     { SK_ScalarMax, 0 },
31     { 0, SK_ScalarMax },
32     { SK_ScalarMax, SK_ScalarMax },
33     { SK_ScalarMin, 0 },
34     { 0, SK_ScalarMin },
35     { SK_ScalarMin, SK_ScalarMin },
36 };
37 
38 const size_t finitePtsCount = sizeof(finitePts) / sizeof(finitePts[0]);
39 
failOne(skiatest::Reporter * reporter,int index)40 static void failOne(skiatest::Reporter* reporter, int index) {
41     SkPath path;
42     int i = (int) (index % nonFinitePtsCount);
43     int f = (int) (index % finitePtsCount);
44     int g = (int) ((f + 1) % finitePtsCount);
45     switch (index % 13) {
46         case 0: path.lineTo(nonFinitePts[i]); break;
47         case 1: path.quadTo(nonFinitePts[i], nonFinitePts[i]); break;
48         case 2: path.quadTo(nonFinitePts[i], finitePts[f]); break;
49         case 3: path.quadTo(finitePts[f], nonFinitePts[i]); break;
50         case 4: path.cubicTo(nonFinitePts[i], finitePts[f], finitePts[f]); break;
51         case 5: path.cubicTo(finitePts[f], nonFinitePts[i], finitePts[f]); break;
52         case 6: path.cubicTo(finitePts[f], finitePts[f], nonFinitePts[i]); break;
53         case 7: path.cubicTo(nonFinitePts[i], nonFinitePts[i], finitePts[f]); break;
54         case 8: path.cubicTo(nonFinitePts[i], finitePts[f], nonFinitePts[i]); break;
55         case 9: path.cubicTo(finitePts[f], nonFinitePts[i], nonFinitePts[i]); break;
56         case 10: path.cubicTo(nonFinitePts[i], nonFinitePts[i], nonFinitePts[i]); break;
57         case 11: path.cubicTo(nonFinitePts[i], finitePts[f], finitePts[g]); break;
58         case 12: path.moveTo(nonFinitePts[i]); break;
59     }
60     SkPath result;
61     result.setFillType(SkPath::kWinding_FillType);
62     bool success = Simplify(path, &result);
63     REPORTER_ASSERT(reporter, !success);
64     REPORTER_ASSERT(reporter, result.isEmpty());
65     REPORTER_ASSERT(reporter, result.getFillType() == SkPath::kWinding_FillType);
66     reporter->bumpTestCount();
67 }
68 
dontFailOne(skiatest::Reporter * reporter,int index)69 static void dontFailOne(skiatest::Reporter* reporter, int index) {
70     SkPath path;
71     int f = (int) (index % finitePtsCount);
72     int g = (int) ((f + 1) % finitePtsCount);
73     switch (index % 11) {
74         case 0: path.lineTo(finitePts[f]); break;
75         case 1: path.quadTo(finitePts[f], finitePts[f]); break;
76         case 2: path.quadTo(finitePts[f], finitePts[g]); break;
77         case 3: path.quadTo(finitePts[g], finitePts[f]); break;
78         case 4: path.cubicTo(finitePts[f], finitePts[f], finitePts[f]); break;
79         case 5: path.cubicTo(finitePts[f], finitePts[f], finitePts[g]); break;
80         case 6: path.cubicTo(finitePts[f], finitePts[g], finitePts[f]); break;
81         case 7: path.cubicTo(finitePts[f], finitePts[g], finitePts[g]); break;
82         case 8: path.cubicTo(finitePts[g], finitePts[f], finitePts[f]); break;
83         case 9: path.cubicTo(finitePts[g], finitePts[f], finitePts[g]); break;
84         case 10: path.moveTo(finitePts[f]); break;
85     }
86     SkPath result;
87     result.setFillType(SkPath::kWinding_FillType);
88     bool success = Simplify(path, &result);
89     if (index != 17 && index != 31 && index != 38) {  // cubic fails to chop in two without creating NaNs
90         REPORTER_ASSERT(reporter, success);
91         REPORTER_ASSERT(reporter, result.getFillType() != SkPath::kWinding_FillType);
92     }
93     reporter->bumpTestCount();
94 }
95 
DEF_TEST(PathOpsSimplifyFail,reporter)96 DEF_TEST(PathOpsSimplifyFail, reporter) {
97     for (int index = 0; index < (int) (13 * nonFinitePtsCount * finitePtsCount); ++index) {
98         failOne(reporter, index);
99     }
100     for (int index = 0; index < (int) (11 * finitePtsCount); ++index) {
101         dontFailOne(reporter, index);
102     }
103 }
104 
DEF_TEST(PathOpsSimplifyFailOne,reporter)105 DEF_TEST(PathOpsSimplifyFailOne, reporter) {
106     int index = 0;
107     failOne(reporter, index);
108 }
109 
DEF_TEST(PathOpsSimplifyDontFailOne,reporter)110 DEF_TEST(PathOpsSimplifyDontFailOne, reporter) {
111     int index = 17;
112     dontFailOne(reporter, index);
113 }
114