blob: f421ee87b63db66660565e1c426e0471afd4b18e [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.com9d5f76a2012-05-01 14:49:28 +000079// Need to exercise drawing an inverse-path whose bounds intersect the clip,
80// but whose edges do not (since its a quad which draws only in the bottom half
81// of its bounds).
82// In the debug build, we used to assert in this case, until it was fixed.
83//
84static void test_inversepathwithclip(skiatest::Reporter* reporter) {
85 SkPath path;
86
87 path.moveTo(0, SkIntToScalar(20));
88 path.quadTo(SkIntToScalar(10), SkIntToScalar(10),
89 SkIntToScalar(20), SkIntToScalar(20));
90 path.toggleInverseFillType();
91
92 SkPaint paint;
93
94 SkAutoTUnref<SkCanvas> canvas(new_canvas(640, 480));
95 canvas.get()->save();
96 canvas.get()->clipRect(SkRect::MakeWH(SkIntToScalar(19), SkIntToScalar(11)));
97
98 paint.setAntiAlias(false);
99 canvas.get()->drawPath(path, paint);
100 paint.setAntiAlias(true);
101 canvas.get()->drawPath(path, paint);
102
103 canvas.get()->restore();
104
105 // Now do the test again, with the path flipped, so we only draw in the
106 // top half of our bounds, and have the clip intersect our bounds at the
107 // bottom.
108 path.reset(); // preserves our filltype
109 path.moveTo(0, SkIntToScalar(10));
110 path.quadTo(SkIntToScalar(10), SkIntToScalar(20),
111 SkIntToScalar(20), SkIntToScalar(10));
112 canvas.get()->clipRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(19),
113 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
mike@reedtribe.org6093e652012-04-14 12:55:17 +0000121static void test_bug533(skiatest::Reporter* reporter) {
122#ifdef SK_SCALAR_IS_FLOAT
123 /*
124 http://code.google.com/p/skia/issues/detail?id=533
125 This particular test/bug only applies to the float case, where the
126 coordinates are very large.
127 */
128 SkPath path;
129 path.moveTo(64, 3);
130 path.quadTo(-329936, -100000000, 1153, 330003);
131
132 SkPaint paint;
133 paint.setAntiAlias(true);
134
135 SkAutoTUnref<SkCanvas> canvas(new_canvas(640, 480));
136 canvas.get()->drawPath(path, paint);
137#endif
138}
139
reed@google.comd9ee3482012-08-06 14:58:35 +0000140static void test_crbug_140642(skiatest::Reporter* reporter) {
141 /*
142 * We used to see this construct, and due to rounding as we accumulated
143 * our length, the loop where we apply the phase would run off the end of
144 * the array, since it relied on just -= each interval value, which did not
145 * behave as "expected". Now the code explicitly checks for walking off the
146 * end of that array.
147
148 * A different (better) fix might be to rewrite dashing to do all of its
149 * length/phase/measure math using double, but this may need to be
150 * coordinated with SkPathMeasure, to be consistent between the two.
151
152 <path stroke="mintcream" stroke-dasharray="27734 35660 2157846850 247"
153 stroke-dashoffset="-248.135982067">
154 */
155
156#ifdef SK_SCALAR_IS_FLOAT
157 const SkScalar vals[] = { 27734, 35660, 2157846850.0f, 247 };
158 SkDashPathEffect dontAssert(vals, 4, -248.135982067f);
159#endif
160}
161
reed@google.com1df888b2012-04-24 22:47:21 +0000162static void test_crbug_124652(skiatest::Reporter* reporter) {
163#ifdef SK_SCALAR_IS_FLOAT
164 /*
165 http://code.google.com/p/chromium/issues/detail?id=124652
166 This particular test/bug only applies to the float case, where
167 large values can "swamp" small ones.
168 */
169 SkScalar intervals[2] = {837099584, 33450};
170 SkAutoTUnref<SkDashPathEffect> dash(
171 new SkDashPathEffect(intervals, 2, -10, false));
172#endif
173}
174
reed@google.coma90aa532012-04-16 16:27:09 +0000175static void test_bigcubic(skiatest::Reporter* reporter) {
176#ifdef SK_SCALAR_IS_FLOAT
177 SkPath path;
178 path.moveTo(64, 3);
179 path.cubicTo(-329936, -100000000, -329936, 100000000, 1153, 330003);
180
181 SkPaint paint;
182 paint.setAntiAlias(true);
183
184 SkAutoTUnref<SkCanvas> canvas(new_canvas(640, 480));
185 canvas.get()->drawPath(path, paint);
186#endif
187}
188
reed@google.comdceecc72012-02-23 19:20:19 +0000189// we used to assert if the bounds of the device (clip) was larger than 32K
190// even when the path itself was smaller. We just draw and hope in the debug
191// version to not assert.
192static void test_giantaa(skiatest::Reporter* reporter) {
193 const int W = 400;
194 const int H = 400;
mike@reedtribe.org6093e652012-04-14 12:55:17 +0000195 SkAutoTUnref<SkCanvas> canvas(new_canvas(33000, 10));
196 canvas.get()->clear(0);
reed@google.comdceecc72012-02-23 19:20:19 +0000197
198 SkPaint paint;
199 paint.setAntiAlias(true);
200 SkPath path;
201 path.addOval(SkRect::MakeXYWH(-10, -10, 20 + W, 20 + H));
mike@reedtribe.org6093e652012-04-14 12:55:17 +0000202 canvas.get()->drawPath(path, paint);
reed@google.comdceecc72012-02-23 19:20:19 +0000203}
204
205static void TestDrawPath(skiatest::Reporter* reporter) {
206 test_giantaa(reporter);
mike@reedtribe.org6093e652012-04-14 12:55:17 +0000207 test_bug533(reporter);
reed@google.coma90aa532012-04-16 16:27:09 +0000208 test_bigcubic(reporter);
reed@google.com1df888b2012-04-24 22:47:21 +0000209 test_crbug_124652(reporter);
reed@google.comd9ee3482012-08-06 14:58:35 +0000210 test_crbug_140642(reporter);
reed@google.com9d5f76a2012-05-01 14:49:28 +0000211 test_inversepathwithclip(reporter);
reed@google.comb59ed512012-06-15 18:26:04 +0000212// test_crbug131181(reporter);
reed@google.comdceecc72012-02-23 19:20:19 +0000213}
214
215#include "TestClassDef.h"
216DEFINE_TESTCLASS("DrawPath", TestDrawPathClass, TestDrawPath)