• 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 "Test.h"
9 #include "SkBitmap.h"
10 #include "SkCanvas.h"
11 #include "SkDashPathEffect.h"
12 
create(SkBitmap::Config config,int w,int h,int rb,void * addr=NULL)13 static SkCanvas* create(SkBitmap::Config config, int w, int h, int rb,
14                         void* addr = NULL) {
15     SkBitmap bm;
16     bm.setConfig(config, w, h, rb);
17     if (addr) {
18         bm.setPixels(addr);
19     } else {
20         bm.allocPixels();
21     }
22     return new SkCanvas(bm);
23 }
24 
new_canvas(int w,int h)25 static SkCanvas* new_canvas(int w, int h) {
26     return create(SkBitmap::kARGB_8888_Config, w, h, 0, NULL);
27 }
28 
29 ///////////////////////////////////////////////////////////////////////////////
30 
moveToH(SkPath * path,const uint32_t raw[])31 static void moveToH(SkPath* path, const uint32_t raw[]) {
32     const float* fptr = (const float*)raw;
33     path->moveTo(fptr[0], fptr[1]);
34 }
35 
cubicToH(SkPath * path,const uint32_t raw[])36 static void cubicToH(SkPath* path, const uint32_t raw[]) {
37     const float* fptr = (const float*)raw;
38     path->cubicTo(fptr[0], fptr[1], fptr[2], fptr[3], fptr[4], fptr[5]);
39 }
40 
41 // This used to assert, because we performed a cast (int)(pt[0].fX * scale) to
42 // arrive at an int (SkFDot6) rather than calling sk_float_round2int. The assert
43 // was that the initial line-segment produced by the cubic was not monotonically
44 // going down (i.e. the initial DY was negative). By rounding the floats, we get
45 // the more proper result.
46 //
47 // http://code.google.com/p/chromium/issues/detail?id=131181
48 //
49 
50 // we're not calling this test anymore; is that for a reason?
51 
test_crbug131181(skiatest::Reporter *)52 static void test_crbug131181(skiatest::Reporter*) {
53     /*
54      fX = 18.8943768,
55      fY = 129.121277
56      }, {
57      fX = 18.8937435,
58      fY = 129.121689
59      }, {
60      fX = 18.8950119,
61      fY = 129.120422
62      }, {
63      fX = 18.5030727,
64      fY = 129.13121
65      */
66     uint32_t data[] = {
67         0x419727af, 0x43011f0c, 0x41972663, 0x43011f27,
68         0x419728fc, 0x43011ed4, 0x4194064b, 0x43012197
69     };
70 
71     SkPath path;
72     moveToH(&path, &data[0]);
73     cubicToH(&path, &data[2]);
74 
75     SkAutoTUnref<SkCanvas> canvas(new_canvas(640, 480));
76 
77     SkPaint paint;
78     paint.setAntiAlias(true);
79     canvas->drawPath(path, paint);
80 }
81 
82 // This used to assert in debug builds (and crash writing bad memory in release)
83 // because we overflowed an intermediate value (B coefficient) setting up our
84 // stepper for the quadratic. Now we bias that value by 1/2 so we don't overflow
test_crbug_140803(skiatest::Reporter * reporter)85 static void test_crbug_140803(skiatest::Reporter* reporter) {
86     SkBitmap bm;
87     bm.setConfig(SkBitmap::kARGB_8888_Config, 2700, 30*1024);
88     bm.allocPixels();
89     SkCanvas canvas(bm);
90 
91     SkPath path;
92     path.moveTo(2762, 20);
93     path.quadTo(11, 21702, 10, 21706);
94     SkPaint paint;
95     paint.setAntiAlias(true);
96     canvas.drawPath(path, paint);
97 }
98 
99 // Need to exercise drawing an inverse-path whose bounds intersect the clip,
100 // but whose edges do not (since its a quad which draws only in the bottom half
101 // of its bounds).
102 // In the debug build, we used to assert in this case, until it was fixed.
103 //
test_inversepathwithclip(skiatest::Reporter * reporter)104 static void test_inversepathwithclip(skiatest::Reporter* reporter) {
105     SkPath path;
106 
107     path.moveTo(0, SkIntToScalar(20));
108     path.quadTo(SkIntToScalar(10), SkIntToScalar(10),
109                 SkIntToScalar(20), SkIntToScalar(20));
110     path.toggleInverseFillType();
111 
112     SkPaint paint;
113 
114     SkAutoTUnref<SkCanvas> canvas(new_canvas(640, 480));
115     canvas.get()->save();
116     canvas.get()->clipRect(SkRect::MakeWH(SkIntToScalar(19), SkIntToScalar(11)));
117 
118     paint.setAntiAlias(false);
119     canvas.get()->drawPath(path, paint);
120     paint.setAntiAlias(true);
121     canvas.get()->drawPath(path, paint);
122 
123     canvas.get()->restore();
124 
125     // Now do the test again, with the path flipped, so we only draw in the
126     // top half of our bounds, and have the clip intersect our bounds at the
127     // bottom.
128     path.reset();   // preserves our filltype
129     path.moveTo(0, SkIntToScalar(10));
130     path.quadTo(SkIntToScalar(10), SkIntToScalar(20),
131                 SkIntToScalar(20), SkIntToScalar(10));
132     canvas.get()->clipRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(19),
133                                             SkIntToScalar(19), SkIntToScalar(11)));
134 
135     paint.setAntiAlias(false);
136     canvas.get()->drawPath(path, paint);
137     paint.setAntiAlias(true);
138     canvas.get()->drawPath(path, paint);
139 }
140 
test_bug533(skiatest::Reporter * reporter)141 static void test_bug533(skiatest::Reporter* reporter) {
142 #ifdef SK_SCALAR_IS_FLOAT
143     /*
144         http://code.google.com/p/skia/issues/detail?id=533
145         This particular test/bug only applies to the float case, where the
146         coordinates are very large.
147      */
148     SkPath path;
149     path.moveTo(64, 3);
150     path.quadTo(-329936, -100000000, 1153, 330003);
151 
152     SkPaint paint;
153     paint.setAntiAlias(true);
154 
155     SkAutoTUnref<SkCanvas> canvas(new_canvas(640, 480));
156     canvas.get()->drawPath(path, paint);
157 #endif
158 }
159 
test_crbug_140642(skiatest::Reporter * reporter)160 static void test_crbug_140642(skiatest::Reporter* reporter) {
161     /*
162      *  We used to see this construct, and due to rounding as we accumulated
163      *  our length, the loop where we apply the phase would run off the end of
164      *  the array, since it relied on just -= each interval value, which did not
165      *  behave as "expected". Now the code explicitly checks for walking off the
166      *  end of that array.
167 
168      *  A different (better) fix might be to rewrite dashing to do all of its
169      *  length/phase/measure math using double, but this may need to be
170      *  coordinated with SkPathMeasure, to be consistent between the two.
171 
172      <path stroke="mintcream" stroke-dasharray="27734 35660 2157846850 247"
173            stroke-dashoffset="-248.135982067">
174      */
175 
176 #ifdef SK_SCALAR_IS_FLOAT
177     const SkScalar vals[] = { 27734, 35660, 2157846850.0f, 247 };
178     SkDashPathEffect dontAssert(vals, 4, -248.135982067f);
179 #endif
180 }
181 
test_crbug_124652(skiatest::Reporter * reporter)182 static void test_crbug_124652(skiatest::Reporter* reporter) {
183 #ifdef SK_SCALAR_IS_FLOAT
184     /*
185         http://code.google.com/p/chromium/issues/detail?id=124652
186         This particular test/bug only applies to the float case, where
187         large values can "swamp" small ones.
188      */
189     SkScalar intervals[2] = {837099584, 33450};
190     SkAutoTUnref<SkDashPathEffect> dash(
191         new SkDashPathEffect(intervals, 2, -10, false));
192 #endif
193 }
194 
test_bigcubic(skiatest::Reporter * reporter)195 static void test_bigcubic(skiatest::Reporter* reporter) {
196 #ifdef SK_SCALAR_IS_FLOAT
197     SkPath path;
198     path.moveTo(64, 3);
199     path.cubicTo(-329936, -100000000, -329936, 100000000, 1153, 330003);
200 
201     SkPaint paint;
202     paint.setAntiAlias(true);
203 
204     SkAutoTUnref<SkCanvas> canvas(new_canvas(640, 480));
205     canvas.get()->drawPath(path, paint);
206 #endif
207 }
208 
209 // we used to assert if the bounds of the device (clip) was larger than 32K
210 // even when the path itself was smaller. We just draw and hope in the debug
211 // version to not assert.
test_giantaa(skiatest::Reporter * reporter)212 static void test_giantaa(skiatest::Reporter* reporter) {
213     const int W = 400;
214     const int H = 400;
215     SkAutoTUnref<SkCanvas> canvas(new_canvas(33000, 10));
216     canvas.get()->clear(SK_ColorTRANSPARENT);
217 
218     SkPaint paint;
219     paint.setAntiAlias(true);
220     SkPath path;
221     path.addOval(SkRect::MakeXYWH(-10, -10, 20 + W, 20 + H));
222     canvas.get()->drawPath(path, paint);
223 }
224 
225 // Extremely large path_length/dash_length ratios may cause infinite looping
226 // in SkDashPathEffect::filterPath() due to single precision rounding.
227 // The test is quite expensive, but it should get much faster after the fix
228 // for http://crbug.com/165432 goes in.
test_infinite_dash(skiatest::Reporter * reporter)229 static void test_infinite_dash(skiatest::Reporter* reporter) {
230     SkPath path;
231     path.moveTo(0, 0);
232     path.lineTo(5000000, 0);
233 
234     SkScalar intervals[] = { 0.2f, 0.2f };
235     SkDashPathEffect dash(intervals, 2, 0);
236 
237     SkPath filteredPath;
238     SkPaint paint;
239     paint.setStyle(SkPaint::kStroke_Style);
240     paint.setPathEffect(&dash);
241 
242     paint.getFillPath(path, &filteredPath);
243     // If we reach this, we passed.
244     REPORTER_ASSERT(reporter, true);
245 }
246 
247 // http://crbug.com/165432
248 // Limit extreme dash path effects to avoid exhausting the system memory.
test_crbug_165432(skiatest::Reporter * reporter)249 static void test_crbug_165432(skiatest::Reporter* reporter) {
250     SkPath path;
251     path.moveTo(0, 0);
252     path.lineTo(10000000, 0);
253 
254     SkScalar intervals[] = { 0.5f, 0.5f };
255     SkDashPathEffect dash(intervals, 2, 0);
256 
257     SkPaint paint;
258     paint.setStyle(SkPaint::kStroke_Style);
259     paint.setPathEffect(&dash);
260 
261     SkPath filteredPath;
262     SkStrokeRec rec(paint);
263     REPORTER_ASSERT(reporter, !dash.filterPath(&filteredPath, path, &rec, NULL));
264     REPORTER_ASSERT(reporter, filteredPath.isEmpty());
265 }
266 
TestDrawPath(skiatest::Reporter * reporter)267 static void TestDrawPath(skiatest::Reporter* reporter) {
268     test_giantaa(reporter);
269     test_bug533(reporter);
270     test_bigcubic(reporter);
271     test_crbug_124652(reporter);
272     test_crbug_140642(reporter);
273     test_crbug_140803(reporter);
274     test_inversepathwithclip(reporter);
275     // why?
276     if (false) test_crbug131181(reporter);
277     test_infinite_dash(reporter);
278     test_crbug_165432(reporter);
279 }
280 
281 #include "TestClassDef.h"
282 DEFINE_TESTCLASS("DrawPath", TestDrawPathClass, TestDrawPath)
283