blob: 8b787bb197d411283923d56dc8a6aa5cd74accc1 [file] [log] [blame]
reed@google.comdceecc72012-02-23 19:20:19 +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
8#include "Test.h"
9#include "SkBitmap.h"
10#include "SkCanvas.h"
reed@google.com1df888b2012-04-24 22:47:21 +000011#include "SkDashPathEffect.h"
reed@google.comdceecc72012-02-23 19:20:19 +000012
13static 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
mike@reedtribe.org6093e652012-04-14 12:55:17 +000025static SkCanvas* new_canvas(int w, int h) {
26 return create(SkBitmap::kARGB_8888_Config, w, h, 0, NULL);
27}
28
reed@google.coma90aa532012-04-16 16:27:09 +000029///////////////////////////////////////////////////////////////////////////////
30
reed@google.comb59ed512012-06-15 18:26:04 +000031static void moveToH(SkPath* path, const uint32_t raw[]) {
32 const float* fptr = (const float*)raw;
33 path->moveTo(fptr[0], fptr[1]);
34}
35
36static 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//
49static void test_crbug131181(skiatest::Reporter*) {
50 /*
51 fX = 18.8943768,
52 fY = 129.121277
53 }, {
54 fX = 18.8937435,
55 fY = 129.121689
56 }, {
57 fX = 18.8950119,
58 fY = 129.120422
59 }, {
60 fX = 18.5030727,
61 fY = 129.13121
62 */
63 uint32_t data[] = {
64 0x419727af, 0x43011f0c, 0x41972663, 0x43011f27,
65 0x419728fc, 0x43011ed4, 0x4194064b, 0x43012197
66 };
67
68 SkPath path;
69 moveToH(&path, &data[0]);
70 cubicToH(&path, &data[2]);
71
72 SkAutoTUnref<SkCanvas> canvas(new_canvas(640, 480));
73
74 SkPaint paint;
75 paint.setAntiAlias(true);
76 canvas->drawPath(path, paint);
77}
78
reed@google.come2faf172012-08-06 19:01:34 +000079// This used to assert in debug builds (and crash writing bad memory in release)
80// because we overflowed an intermediate value (B coefficient) setting up our
81// stepper for the quadratic. Now we bias that value by 1/2 so we don't overflow
82static void test_crbug_140803(skiatest::Reporter* reporter) {
83 SkBitmap bm;
84 bm.setConfig(SkBitmap::kARGB_8888_Config, 2700, 30*1024);
85 bm.allocPixels();
86 SkCanvas canvas(bm);
87
88 SkPath path;
89 path.moveTo(2762, 20);
90 path.quadTo(11, 21702, 10, 21706);
91 SkPaint paint;
92 paint.setAntiAlias(true);
93 canvas.drawPath(path, paint);
94}
95
reed@google.com9d5f76a2012-05-01 14:49:28 +000096// Need to exercise drawing an inverse-path whose bounds intersect the clip,
97// but whose edges do not (since its a quad which draws only in the bottom half
98// of its bounds).
99// In the debug build, we used to assert in this case, until it was fixed.
100//
101static void test_inversepathwithclip(skiatest::Reporter* reporter) {
102 SkPath path;
103
104 path.moveTo(0, SkIntToScalar(20));
105 path.quadTo(SkIntToScalar(10), SkIntToScalar(10),
106 SkIntToScalar(20), SkIntToScalar(20));
107 path.toggleInverseFillType();
108
109 SkPaint paint;
110
111 SkAutoTUnref<SkCanvas> canvas(new_canvas(640, 480));
112 canvas.get()->save();
113 canvas.get()->clipRect(SkRect::MakeWH(SkIntToScalar(19), SkIntToScalar(11)));
114
115 paint.setAntiAlias(false);
116 canvas.get()->drawPath(path, paint);
117 paint.setAntiAlias(true);
118 canvas.get()->drawPath(path, paint);
119
120 canvas.get()->restore();
121
122 // Now do the test again, with the path flipped, so we only draw in the
123 // top half of our bounds, and have the clip intersect our bounds at the
124 // bottom.
125 path.reset(); // preserves our filltype
126 path.moveTo(0, SkIntToScalar(10));
127 path.quadTo(SkIntToScalar(10), SkIntToScalar(20),
128 SkIntToScalar(20), SkIntToScalar(10));
129 canvas.get()->clipRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(19),
130 SkIntToScalar(19), SkIntToScalar(11)));
131
132 paint.setAntiAlias(false);
133 canvas.get()->drawPath(path, paint);
134 paint.setAntiAlias(true);
135 canvas.get()->drawPath(path, paint);
136}
137
mike@reedtribe.org6093e652012-04-14 12:55:17 +0000138static void test_bug533(skiatest::Reporter* reporter) {
139#ifdef SK_SCALAR_IS_FLOAT
140 /*
141 http://code.google.com/p/skia/issues/detail?id=533
142 This particular test/bug only applies to the float case, where the
143 coordinates are very large.
144 */
145 SkPath path;
146 path.moveTo(64, 3);
147 path.quadTo(-329936, -100000000, 1153, 330003);
148
149 SkPaint paint;
150 paint.setAntiAlias(true);
151
152 SkAutoTUnref<SkCanvas> canvas(new_canvas(640, 480));
153 canvas.get()->drawPath(path, paint);
154#endif
155}
156
reed@google.comd9ee3482012-08-06 14:58:35 +0000157static void test_crbug_140642(skiatest::Reporter* reporter) {
158 /*
159 * We used to see this construct, and due to rounding as we accumulated
160 * our length, the loop where we apply the phase would run off the end of
161 * the array, since it relied on just -= each interval value, which did not
162 * behave as "expected". Now the code explicitly checks for walking off the
163 * end of that array.
164
165 * A different (better) fix might be to rewrite dashing to do all of its
166 * length/phase/measure math using double, but this may need to be
167 * coordinated with SkPathMeasure, to be consistent between the two.
168
169 <path stroke="mintcream" stroke-dasharray="27734 35660 2157846850 247"
170 stroke-dashoffset="-248.135982067">
171 */
172
173#ifdef SK_SCALAR_IS_FLOAT
174 const SkScalar vals[] = { 27734, 35660, 2157846850.0f, 247 };
175 SkDashPathEffect dontAssert(vals, 4, -248.135982067f);
176#endif
177}
178
reed@google.com1df888b2012-04-24 22:47:21 +0000179static void test_crbug_124652(skiatest::Reporter* reporter) {
180#ifdef SK_SCALAR_IS_FLOAT
181 /*
182 http://code.google.com/p/chromium/issues/detail?id=124652
183 This particular test/bug only applies to the float case, where
184 large values can "swamp" small ones.
185 */
186 SkScalar intervals[2] = {837099584, 33450};
187 SkAutoTUnref<SkDashPathEffect> dash(
188 new SkDashPathEffect(intervals, 2, -10, false));
189#endif
190}
191
reed@google.coma90aa532012-04-16 16:27:09 +0000192static void test_bigcubic(skiatest::Reporter* reporter) {
193#ifdef SK_SCALAR_IS_FLOAT
194 SkPath path;
195 path.moveTo(64, 3);
196 path.cubicTo(-329936, -100000000, -329936, 100000000, 1153, 330003);
197
198 SkPaint paint;
199 paint.setAntiAlias(true);
200
201 SkAutoTUnref<SkCanvas> canvas(new_canvas(640, 480));
202 canvas.get()->drawPath(path, paint);
203#endif
204}
205
reed@google.comdceecc72012-02-23 19:20:19 +0000206// we used to assert if the bounds of the device (clip) was larger than 32K
207// even when the path itself was smaller. We just draw and hope in the debug
208// version to not assert.
209static void test_giantaa(skiatest::Reporter* reporter) {
210 const int W = 400;
211 const int H = 400;
mike@reedtribe.org6093e652012-04-14 12:55:17 +0000212 SkAutoTUnref<SkCanvas> canvas(new_canvas(33000, 10));
213 canvas.get()->clear(0);
reed@google.comdceecc72012-02-23 19:20:19 +0000214
215 SkPaint paint;
216 paint.setAntiAlias(true);
217 SkPath path;
218 path.addOval(SkRect::MakeXYWH(-10, -10, 20 + W, 20 + H));
mike@reedtribe.org6093e652012-04-14 12:55:17 +0000219 canvas.get()->drawPath(path, paint);
reed@google.comdceecc72012-02-23 19:20:19 +0000220}
221
222static void TestDrawPath(skiatest::Reporter* reporter) {
223 test_giantaa(reporter);
mike@reedtribe.org6093e652012-04-14 12:55:17 +0000224 test_bug533(reporter);
reed@google.coma90aa532012-04-16 16:27:09 +0000225 test_bigcubic(reporter);
reed@google.com1df888b2012-04-24 22:47:21 +0000226 test_crbug_124652(reporter);
reed@google.comd9ee3482012-08-06 14:58:35 +0000227 test_crbug_140642(reporter);
reed@google.come2faf172012-08-06 19:01:34 +0000228 test_crbug_140803(reporter);
reed@google.com9d5f76a2012-05-01 14:49:28 +0000229 test_inversepathwithclip(reporter);
reed@google.comb59ed512012-06-15 18:26:04 +0000230// test_crbug131181(reporter);
reed@google.comdceecc72012-02-23 19:20:19 +0000231}
232
233#include "TestClassDef.h"
234DEFINE_TESTCLASS("DrawPath", TestDrawPathClass, TestDrawPath)