• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
8 #include "include/core/SkPaint.h"
9 #include "include/core/SkPath.h"
10 #include "include/core/SkRect.h"
11 #include "include/core/SkStrokeRec.h"
12 #include "src/core/SkPathPriv.h"
13 #include "src/core/SkStroke.h"
14 #include "tests/Test.h"
15 
equal(const SkRect & a,const SkRect & b)16 static 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 
test_strokecubic(skiatest::Reporter * reporter)23 static 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 
test_strokerect(skiatest::Reporter * reporter)52 static 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()));
76 
77         bool isMiter = SkPaint::kMiter_Join == joins[i];
78         SkRect nested[2];
79         REPORTER_ASSERT(reporter, SkPathPriv::IsNestedFillRects(fillPath, nested) == isMiter);
80         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 
test_strokerec_equality(skiatest::Reporter * reporter)89 static 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));  // Miter limit not relevant to butt caps.
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 
164 // From skbug.com/6491. The large stroke width can cause numerical instabilities.
test_big_stroke(skiatest::Reporter * reporter)165 static 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;
171     path.moveTo(SkBits2Float(0x46380000), SkBits2Float(0xc6380000));  // 11776, -11776
172     path.lineTo(SkBits2Float(0x46a00000), SkBits2Float(0xc6a00000));  // 20480, -20480
173     path.lineTo(SkBits2Float(0x468c0000), SkBits2Float(0xc68c0000));  // 17920, -17920
174     path.lineTo(SkBits2Float(0x46100000), SkBits2Float(0xc6100000));  // 9216, -9216
175     path.lineTo(SkBits2Float(0x46380000), SkBits2Float(0xc6380000));  // 11776, -11776
176     path.close();
177 
178     SkPath strokeAndFillPath;
179     paint.getFillPath(path, &strokeAndFillPath);
180 }
181 
DEF_TEST(Stroke,reporter)182 DEF_TEST(Stroke, reporter) {
183     test_strokecubic(reporter);
184     test_strokerect(reporter);
185     test_strokerec_equality(reporter);
186     test_big_stroke(reporter);
187 }
188