• 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 "SkPaint.h"
9 #include "SkPath.h"
10 #include "SkRect.h"
11 #include "SkStroke.h"
12 #include "SkStrokeRec.h"
13 #include "Test.h"
14 
equal(const SkRect & a,const SkRect & b)15 static bool equal(const SkRect& a, const SkRect& b) {
16     return  SkScalarNearlyEqual(a.left(), b.left()) &&
17             SkScalarNearlyEqual(a.top(), b.top()) &&
18             SkScalarNearlyEqual(a.right(), b.right()) &&
19             SkScalarNearlyEqual(a.bottom(), b.bottom());
20 }
21 
test_strokecubic(skiatest::Reporter * reporter)22 static void test_strokecubic(skiatest::Reporter* reporter) {
23     uint32_t hexCubicVals[] = {
24         0x424c1086, 0x44bcf0cb,  // fX=51.0161362 fY=1511.52478
25         0x424c107c, 0x44bcf0cb,  // fX=51.0160980 fY=1511.52478
26         0x424c10c2, 0x44bcf0cb,  // fX=51.0163651 fY=1511.52478
27         0x424c1119, 0x44bcf0ca,  // fX=51.0166969 fY=1511.52466
28     };
29     SkPoint cubicVals[] = {
30         {51.0161362f, 1511.52478f },
31         {51.0160980f, 1511.52478f },
32         {51.0163651f, 1511.52478f },
33         {51.0166969f, 1511.52466f },
34     };
35     SkPaint paint;
36 
37     paint.setStyle(SkPaint::kStroke_Style);
38     paint.setStrokeWidth(0.394537568f);
39     SkPath path, fillPath;
40     path.moveTo(cubicVals[0]);
41     path.cubicTo(cubicVals[1], cubicVals[2], cubicVals[3]);
42     paint.getFillPath(path, &fillPath);
43     path.reset();
44     path.moveTo(SkBits2Float(hexCubicVals[0]), SkBits2Float(hexCubicVals[1]));
45     path.cubicTo(SkBits2Float(hexCubicVals[2]), SkBits2Float(hexCubicVals[3]),
46             SkBits2Float(hexCubicVals[4]), SkBits2Float(hexCubicVals[5]),
47             SkBits2Float(hexCubicVals[6]), SkBits2Float(hexCubicVals[7]));
48     paint.getFillPath(path, &fillPath);
49 }
50 
test_strokerect(skiatest::Reporter * reporter)51 static void test_strokerect(skiatest::Reporter* reporter) {
52     const SkScalar width = SkIntToScalar(10);
53     SkPaint paint;
54 
55     paint.setStyle(SkPaint::kStroke_Style);
56     paint.setStrokeWidth(width);
57 
58     SkRect r = { 0, 0, SkIntToScalar(200), SkIntToScalar(100) };
59 
60     SkRect outer(r);
61     outer.outset(width/2, width/2);
62 
63     static const SkPaint::Join joins[] = {
64         SkPaint::kMiter_Join, SkPaint::kRound_Join, SkPaint::kBevel_Join
65     };
66 
67     for (size_t i = 0; i < SK_ARRAY_COUNT(joins); ++i) {
68         paint.setStrokeJoin(joins[i]);
69 
70         SkPath path, fillPath;
71         path.addRect(r);
72         paint.getFillPath(path, &fillPath);
73 
74         REPORTER_ASSERT(reporter, equal(outer, fillPath.getBounds()));
75 
76         bool isMiter = SkPaint::kMiter_Join == joins[i];
77         SkRect nested[2];
78         REPORTER_ASSERT(reporter, fillPath.isNestedFillRects(nested) == isMiter);
79         if (isMiter) {
80             SkRect inner(r);
81             inner.inset(width/2, width/2);
82             REPORTER_ASSERT(reporter, equal(nested[0], outer));
83             REPORTER_ASSERT(reporter, equal(nested[1], inner));
84         }
85     }
86 }
87 
test_strokerec_equality(skiatest::Reporter * reporter)88 static void test_strokerec_equality(skiatest::Reporter* reporter) {
89     {
90         SkStrokeRec s1(SkStrokeRec::kFill_InitStyle);
91         SkStrokeRec s2(SkStrokeRec::kFill_InitStyle);
92         REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
93 
94         // Test that style mismatch is detected.
95         s2.setHairlineStyle();
96         REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
97 
98         s1.setHairlineStyle();
99         REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
100 
101         // ResScale is not part of equality.
102         s1.setResScale(2.1f);
103         s2.setResScale(1.2f);
104         REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
105         s1.setFillStyle();
106         s2.setFillStyle();
107         REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
108         s1.setStrokeStyle(1.0f, false);
109         s2.setStrokeStyle(1.0f, false);
110         s1.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.9f);
111         s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.9f);
112         REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
113     }
114 
115     // Stroke parameters on fill or hairline style are not part of equality.
116     {
117         SkStrokeRec s1(SkStrokeRec::kFill_InitStyle);
118         SkStrokeRec s2(SkStrokeRec::kFill_InitStyle);
119         for (int i = 0; i < 2; ++i) {
120             s1.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.9f);
121             s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.1f);
122             REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
123             s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kBevel_Join, 2.9f);
124             REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
125             s2.setStrokeParams(SkPaint::kRound_Cap, SkPaint::kRound_Join, 2.9f);
126             REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
127             s1.setHairlineStyle();
128             s2.setHairlineStyle();
129         }
130     }
131 
132     // Stroke parameters on stroke style are part of equality.
133     {
134         SkStrokeRec s1(SkStrokeRec::kFill_InitStyle);
135         SkStrokeRec s2(SkStrokeRec::kFill_InitStyle);
136         s1.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.9f);
137         s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.9f);
138         s1.setStrokeStyle(1.0f, false);
139 
140         s2.setStrokeStyle(1.0f, true);
141         REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
142 
143         s2.setStrokeStyle(2.1f, false);
144         REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
145 
146         s2.setStrokeStyle(1.0f, false);
147         REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
148 
149         s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 2.1f);
150         REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
151         s2.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kBevel_Join, 2.9f);
152         REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
153         s2.setStrokeParams(SkPaint::kRound_Cap, SkPaint::kRound_Join, 2.9f);
154         REPORTER_ASSERT(reporter, !s1.hasEqualEffect(s2));
155 
156         // Sets fill.
157         s1.setStrokeStyle(0.0f, true);
158         s2.setStrokeStyle(0.0f, true);
159         REPORTER_ASSERT(reporter, s1.hasEqualEffect(s2));
160     }
161 }
162 
163 // From skbug.com/6491. The large stroke width can cause numerical instabilities.
test_big_stroke(skiatest::Reporter * reporter)164 static void test_big_stroke(skiatest::Reporter* reporter) {
165     SkPaint paint;
166     paint.setStyle(SkPaint::kStrokeAndFill_Style);
167     paint.setStrokeWidth(1.49679073e+10f);
168 
169     SkPath path;
170     path.setFillType(SkPath::kWinding_FillType);
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