blob: 2cd01539bae95a587a7cd4666a975ad45fafb2f0 [file] [log] [blame]
caryclark@google.comcd4421d2012-03-01 19:16:31 +00001#include "EdgeWalker_Test.h"
2#include "Intersection_Tests.h"
3#include "SkBitmap.h"
4#include "SkCanvas.h"
5#include "SkPaint.h"
6
caryclark@google.com2e7f4c82012-03-20 21:11:59 +00007static bool gShowPath = false;
caryclark@google.com752b60e2012-03-22 21:11:17 +00008static bool gComparePaths = false;
9static bool gDrawLastAsciiPaths = true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +000010static bool gDrawAllAsciiPaths = false;
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000011static bool gShowAsciiPaths = false;
caryclark@google.com752b60e2012-03-22 21:11:17 +000012static bool gComparePathsAssert = true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +000013
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000014void showPath(const SkPath& path, const char* str) {
caryclark@google.com752b60e2012-03-22 21:11:17 +000015 SkDebugf("%s\n", !str ? "original:" : str);
caryclark@google.comcd4421d2012-03-01 19:16:31 +000016 SkPath::Iter iter(path, true);
17 uint8_t verb;
18 SkPoint pts[4];
19 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
20 switch (verb) {
21 case SkPath::kMove_Verb:
caryclark@google.comd88e0892012-03-27 13:23:51 +000022 SkDebugf("path.moveTo(%1.9g, %1.9g);\n", pts[0].fX, pts[0].fY);
caryclark@google.comcd4421d2012-03-01 19:16:31 +000023 continue;
24 case SkPath::kLine_Verb:
caryclark@google.comd88e0892012-03-27 13:23:51 +000025 SkDebugf("path.lineTo(%1.9g, %1.9g);\n", pts[1].fX, pts[1].fY);
caryclark@google.comcd4421d2012-03-01 19:16:31 +000026 break;
27 case SkPath::kQuad_Verb:
caryclark@google.comd88e0892012-03-27 13:23:51 +000028 SkDebugf("path.quadTo(%1.9g, %1.9g, %1.9g, %1.9g);\n",
caryclark@google.comcd4421d2012-03-01 19:16:31 +000029 pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
30 break;
31 case SkPath::kCubic_Verb:
caryclark@google.comd88e0892012-03-27 13:23:51 +000032 SkDebugf("path.cubicTo(%1.9g, %1.9g, %1.9g, %1.9g);\n",
caryclark@google.comcd4421d2012-03-01 19:16:31 +000033 pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY,
34 pts[3].fX, pts[3].fY);
35 break;
36 case SkPath::kClose_Verb:
37 SkDebugf("path.close();\n");
38 continue;
39 default:
40 SkDEBUGFAIL("bad verb");
41 return;
42 }
43 }
44}
45
46static bool pathsDrawTheSame(const SkPath& one, const SkPath& two) {
47 const SkRect& bounds1 = one.getBounds();
48 const SkRect& bounds2 = two.getBounds();
49 SkRect larger = bounds1;
50 larger.join(bounds2);
51 SkBitmap bits;
52 int bitWidth = SkScalarCeil(larger.width()) + 2;
53 int bitHeight = SkScalarCeil(larger.height()) + 2;
54 bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight);
55 bits.allocPixels();
56 SkCanvas canvas(bits);
57 canvas.drawColor(SK_ColorWHITE);
58 SkPaint paint;
59 canvas.save();
60 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
61 canvas.drawPath(one, paint);
62 canvas.restore();
63 canvas.save();
64 canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
65 canvas.drawPath(two, paint);
66 canvas.restore();
67 for (int y = 0; y < bitHeight; ++y) {
68 uint32_t* addr1 = bits.getAddr32(0, y);
69 uint32_t* addr2 = bits.getAddr32(bitWidth, y);
70 for (int x = 0; x < bitWidth; ++x) {
71 if (addr1[x] != addr2[x]) {
72 return false;
73 break;
74 }
75 }
76 }
77 return true;
78}
79
caryclark@google.com752b60e2012-03-22 21:11:17 +000080bool drawAsciiPaths(const SkPath& one, const SkPath& two,
caryclark@google.comcd4421d2012-03-01 19:16:31 +000081 bool drawPaths) {
82 if (!drawPaths) {
caryclark@google.com752b60e2012-03-22 21:11:17 +000083 return true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +000084 }
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000085 if (gShowAsciiPaths) {
86 showPath(one, "one:");
87 showPath(two, "two:");
caryclark@google.comcd4421d2012-03-01 19:16:31 +000088 }
89 const SkRect& bounds1 = one.getBounds();
90 const SkRect& bounds2 = two.getBounds();
91 SkRect larger = bounds1;
92 larger.join(bounds2);
93 SkBitmap bits;
caryclark@google.com752b60e2012-03-22 21:11:17 +000094 char out[256];
caryclark@google.comcd4421d2012-03-01 19:16:31 +000095 int bitWidth = SkScalarCeil(larger.width()) + 2;
caryclark@google.com752b60e2012-03-22 21:11:17 +000096 if (bitWidth * 2 + 1 >= (int) sizeof(out)) {
97 return false;
98 }
caryclark@google.comcd4421d2012-03-01 19:16:31 +000099 int bitHeight = SkScalarCeil(larger.height()) + 2;
caryclark@google.com752b60e2012-03-22 21:11:17 +0000100 if (bitHeight >= (int) sizeof(out)) {
101 return false;
102 }
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000103 bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight);
104 bits.allocPixels();
105 SkCanvas canvas(bits);
106 canvas.drawColor(SK_ColorWHITE);
107 SkPaint paint;
108 canvas.save();
109 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
110 canvas.drawPath(one, paint);
111 canvas.restore();
112 canvas.save();
113 canvas.translate(-bounds2.fLeft + 1 + bitWidth, -bounds2.fTop + 1);
114 canvas.drawPath(two, paint);
115 canvas.restore();
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000116 for (int y = 0; y < bitHeight; ++y) {
117 uint32_t* addr1 = bits.getAddr32(0, y);
118 int x;
119 char* outPtr = out;
120 for (x = 0; x < bitWidth; ++x) {
121 *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x';
122 }
123 *outPtr++ = '|';
124 for (x = bitWidth; x < bitWidth * 2; ++x) {
125 *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x';
126 }
127 *outPtr++ = '\0';
128 SkDebugf("%s\n", out);
129 }
caryclark@google.com752b60e2012-03-22 21:11:17 +0000130 return true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000131}
132
133static bool scaledDrawTheSame(const SkPath& one, const SkPath& two,
134 int a, int b, bool drawPaths) {
135 SkMatrix scale;
136 scale.reset();
caryclark@google.com752b60e2012-03-22 21:11:17 +0000137 float aScale = 1.21f;
138 float bScale = 1.11f;
139 scale.preScale(a * aScale, b * bScale);
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000140 SkPath scaledOne, scaledTwo;
141 one.transform(scale, &scaledOne);
142 two.transform(scale, &scaledTwo);
143 if (pathsDrawTheSame(scaledOne, scaledTwo)) {
144 return true;
145 }
caryclark@google.com752b60e2012-03-22 21:11:17 +0000146 while (!drawAsciiPaths(scaledOne, scaledTwo, drawPaths)) {
147 scale.reset();
148 aScale *= 0.5f;
149 bScale *= 0.5f;
150 scale.preScale(a * aScale, b * bScale);
151 one.transform(scale, &scaledOne);
152 two.transform(scale, &scaledTwo);
153 }
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000154 return false;
155}
156
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000157bool comparePaths(const SkPath& one, const SkPath& two) {
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000158 if (pathsDrawTheSame(one, two)) {
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000159 return true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000160 }
161 drawAsciiPaths(one, two, gDrawAllAsciiPaths);
162 for (int x = 9; x <= 33; ++x) {
163 if (scaledDrawTheSame(one, two, x, x - (x >> 2), gDrawAllAsciiPaths)) {
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000164 return true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000165 }
166 }
167 if (!gDrawAllAsciiPaths) {
168 scaledDrawTheSame(one, two, 9, 7, gDrawLastAsciiPaths);
169 }
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000170 if (gComparePathsAssert) {
171 showPath(one);
172 showPath(two, "simplified:");
173 SkASSERT(0);
174 }
175 return false;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000176}
177
178// doesn't work yet
179void comparePathsTiny(const SkPath& one, const SkPath& two) {
180 const SkRect& bounds1 = one.getBounds();
181 const SkRect& bounds2 = two.getBounds();
182 SkRect larger = bounds1;
183 larger.join(bounds2);
184 SkBitmap bits;
185 int bitWidth = SkScalarCeil(larger.width()) + 2;
186 int bitHeight = SkScalarCeil(larger.height()) + 2;
187 bits.setConfig(SkBitmap::kA1_Config, bitWidth * 2, bitHeight);
188 bits.allocPixels();
189 SkCanvas canvas(bits);
190 canvas.drawColor(SK_ColorWHITE);
191 SkPaint paint;
192 canvas.save();
193 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
194 canvas.drawPath(one, paint);
195 canvas.restore();
196 canvas.save();
197 canvas.translate(-bounds2.fLeft + 1, -bounds2.fTop + 1);
198 canvas.drawPath(two, paint);
199 canvas.restore();
200 for (int y = 0; y < bitHeight; ++y) {
201 uint8_t* addr1 = bits.getAddr1(0, y);
202 uint8_t* addr2 = bits.getAddr1(bitWidth, y);
203 for (int x = 0; x < bits.rowBytes(); ++x) {
204 SkASSERT(addr1[x] == addr2[x]);
205 }
206 }
207}
208
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000209bool testSimplify(const SkPath& path, bool fill, SkPath& out) {
210 if (gShowPath) {
211 showPath(path);
212 }
213 simplify(path, fill, out);
caryclark@google.com752b60e2012-03-22 21:11:17 +0000214 if (!gComparePaths) {
215 return true;
216 }
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000217 return comparePaths(path, out);
218}