blob: e13a775e70ef25138d3a252e33c92f8aa8f16d36 [file] [log] [blame]
reed@google.com603dbed2012-11-20 19:00:28 +00001/*
2 * Copyright 2012 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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkPaint.h"
9#include "include/core/SkPath.h"
10#include "include/core/SkRect.h"
11#include "include/core/SkStrokeRec.h"
Mike Reed430470d2019-09-12 17:09:12 -040012#include "src/core/SkPathPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/core/SkStroke.h"
14#include "tests/Test.h"
reed@google.com603dbed2012-11-20 19:00:28 +000015
16static bool equal(const SkRect& a, const SkRect& b) {
17 return SkScalarNearlyEqual(a.left(), b.left()) &&
18 SkScalarNearlyEqual(a.top(), b.top()) &&
19 SkScalarNearlyEqual(a.right(), b.right()) &&
20 SkScalarNearlyEqual(a.bottom(), b.bottom());
21}
22
caryclark63c684a2015-02-25 09:04:04 -080023static void test_strokecubic(skiatest::Reporter* reporter) {
24 uint32_t hexCubicVals[] = {
25 0x424c1086, 0x44bcf0cb, // fX=51.0161362 fY=1511.52478
26 0x424c107c, 0x44bcf0cb, // fX=51.0160980 fY=1511.52478
27 0x424c10c2, 0x44bcf0cb, // fX=51.0163651 fY=1511.52478
28 0x424c1119, 0x44bcf0ca, // fX=51.0166969 fY=1511.52466
29 };
30 SkPoint cubicVals[] = {
31 {51.0161362f, 1511.52478f },
32 {51.0160980f, 1511.52478f },
33 {51.0163651f, 1511.52478f },
34 {51.0166969f, 1511.52466f },
35 };
36 SkPaint paint;
37
38 paint.setStyle(SkPaint::kStroke_Style);
39 paint.setStrokeWidth(0.394537568f);
40 SkPath path, fillPath;
41 path.moveTo(cubicVals[0]);
42 path.cubicTo(cubicVals[1], cubicVals[2], cubicVals[3]);
43 paint.getFillPath(path, &fillPath);
44 path.reset();
45 path.moveTo(SkBits2Float(hexCubicVals[0]), SkBits2Float(hexCubicVals[1]));
46 path.cubicTo(SkBits2Float(hexCubicVals[2]), SkBits2Float(hexCubicVals[3]),
47 SkBits2Float(hexCubicVals[4]), SkBits2Float(hexCubicVals[5]),
48 SkBits2Float(hexCubicVals[6]), SkBits2Float(hexCubicVals[7]));
49 paint.getFillPath(path, &fillPath);
50}
51
reed@google.com603dbed2012-11-20 19:00:28 +000052static void test_strokerect(skiatest::Reporter* reporter) {
53 const SkScalar width = SkIntToScalar(10);
54 SkPaint paint;
55
56 paint.setStyle(SkPaint::kStroke_Style);
57 paint.setStrokeWidth(width);
58
59 SkRect r = { 0, 0, SkIntToScalar(200), SkIntToScalar(100) };
60
61 SkRect outer(r);
62 outer.outset(width/2, width/2);
63
64 static const SkPaint::Join joins[] = {
65 SkPaint::kMiter_Join, SkPaint::kRound_Join, SkPaint::kBevel_Join
66 };
67
68 for (size_t i = 0; i < SK_ARRAY_COUNT(joins); ++i) {
69 paint.setStrokeJoin(joins[i]);
70
71 SkPath path, fillPath;
72 path.addRect(r);
73 paint.getFillPath(path, &fillPath);
74
75 REPORTER_ASSERT(reporter, equal(outer, fillPath.getBounds()));
skia.committer@gmail.comb0a327e2012-11-21 02:02:25 +000076
reed@google.com603dbed2012-11-20 19:00:28 +000077 bool isMiter = SkPaint::kMiter_Join == joins[i];
78 SkRect nested[2];
Mike Reed430470d2019-09-12 17:09:12 -040079 REPORTER_ASSERT(reporter, SkPathPriv::IsNestedFillRects(fillPath, nested) == isMiter);
reed@google.com603dbed2012-11-20 19:00:28 +000080 if (isMiter) {
81 SkRect inner(r);
82 inner.inset(width/2, width/2);
83 REPORTER_ASSERT(reporter, equal(nested[0], outer));
84 REPORTER_ASSERT(reporter, equal(nested[1], inner));
85 }
86 }
87}
88
kkinnunen8f827fe2015-05-13 00:02:26 -070089static void test_strokerec_equality(skiatest::Reporter* reporter) {
90 {
91 SkStrokeRec s1(SkStrokeRec::kFill_InitStyle);
92 SkStrokeRec s2(SkStrokeRec::kFill_InitStyle);
93 REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
94
95 // Test that style mismatch is detected.
96 s2.setHairlineStyle();
97 REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
98
99 s1.setHairlineStyle();
100 REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
101
102 // ResScale is not part of equality.
103 s1.setResScale(2.1f);
104 s2.setResScale(1.2f);
105 REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
106 s1.setFillStyle();
107 s2.setFillStyle();
108 REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
109 s1.setStrokeStyle(1.0f, false);
110 s2.setStrokeStyle(1.0f, false);
111 s1.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.9f);
112 s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.9f);
113 REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
114 }
115
116 // Stroke parameters on fill or hairline style are not part of equality.
117 {
118 SkStrokeRec s1(SkStrokeRec::kFill_InitStyle);
119 SkStrokeRec s2(SkStrokeRec::kFill_InitStyle);
120 for (int i = 0; i < 2; ++i) {
121 s1.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.9f);
122 s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.1f);
123 REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
124 s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kBevel_Join, 2.9f);
125 REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
126 s2.setStrokeParams(SkPaint::kRound_Cap, SkPaint::kRound_Join, 2.9f);
127 REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
128 s1.setHairlineStyle();
129 s2.setHairlineStyle();
130 }
131 }
132
133 // Stroke parameters on stroke style are part of equality.
134 {
135 SkStrokeRec s1(SkStrokeRec::kFill_InitStyle);
136 SkStrokeRec s2(SkStrokeRec::kFill_InitStyle);
137 s1.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.9f);
138 s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.9f);
139 s1.setStrokeStyle(1.0f, false);
140
141 s2.setStrokeStyle(1.0f, true);
142 REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
143
144 s2.setStrokeStyle(2.1f, false);
145 REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
146
147 s2.setStrokeStyle(1.0f, false);
148 REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
149
150 s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.1f);
151 REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
152 s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kBevel_Join, 2.9f);
153 REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
154 s2.setStrokeParams(SkPaint::kRound_Cap, SkPaint::kRound_Join, 2.9f);
155 REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
156
157 // Sets fill.
158 s1.setStrokeStyle(0.0f, true);
159 s2.setStrokeStyle(0.0f, true);
160 REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
161 }
162}
163
Robert Phillipsd587ebe2018-02-05 09:15:20 -0500164// From skbug.com/6491. The large stroke width can cause numerical instabilities.
165static void test_big_stroke(skiatest::Reporter* reporter) {
166 SkPaint paint;
167 paint.setStyle(SkPaint::kStrokeAndFill_Style);
168 paint.setStrokeWidth(1.49679073e+10f);
169
170 SkPath path;
Mike Reed4241f5e2019-09-14 19:13:23 +0000171 path.setFillType(SkPath::kWinding_FillType);
Robert Phillipsd587ebe2018-02-05 09:15:20 -0500172 path.moveTo(SkBits2Float(0x46380000), SkBits2Float(0xc6380000)); // 11776, -11776
173 path.lineTo(SkBits2Float(0x46a00000), SkBits2Float(0xc6a00000)); // 20480, -20480
174 path.lineTo(SkBits2Float(0x468c0000), SkBits2Float(0xc68c0000)); // 17920, -17920
175 path.lineTo(SkBits2Float(0x46100000), SkBits2Float(0xc6100000)); // 9216, -9216
176 path.lineTo(SkBits2Float(0x46380000), SkBits2Float(0xc6380000)); // 11776, -11776
177 path.close();
178
179 SkPath strokeAndFillPath;
180 paint.getFillPath(path, &strokeAndFillPath);
181}
182
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000183DEF_TEST(Stroke, reporter) {
caryclark63c684a2015-02-25 09:04:04 -0800184 test_strokecubic(reporter);
reed@google.com603dbed2012-11-20 19:00:28 +0000185 test_strokerect(reporter);
kkinnunen8f827fe2015-05-13 00:02:26 -0700186 test_strokerec_equality(reporter);
Robert Phillipsd587ebe2018-02-05 09:15:20 -0500187 test_big_stroke(reporter);
reed@google.com603dbed2012-11-20 19:00:28 +0000188}