blob: 84ca87fce3e805b7d855b2625e77273e796857f3 [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;
8static bool gDrawLastAsciiPaths = false;
caryclark@google.comcd4421d2012-03-01 19:16:31 +00009static bool gDrawAllAsciiPaths = false;
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000010static bool gShowAsciiPaths = false;
11static bool gComparePathsAssert = false;
caryclark@google.comcd4421d2012-03-01 19:16:31 +000012
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000013void showPath(const SkPath& path, const char* str) {
14 SkDebugf("%s\n", str ? "original:" : str);
caryclark@google.comcd4421d2012-03-01 19:16:31 +000015 SkPath::Iter iter(path, true);
16 uint8_t verb;
17 SkPoint pts[4];
18 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
19 switch (verb) {
20 case SkPath::kMove_Verb:
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000021 SkDebugf("path.moveTo(%3.6g, %3.6g);\n", pts[0].fX, pts[0].fY);
caryclark@google.comcd4421d2012-03-01 19:16:31 +000022 continue;
23 case SkPath::kLine_Verb:
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000024 SkDebugf("path.lineTo(%3.6g, %3.6g);\n", pts[1].fX, pts[1].fY);
caryclark@google.comcd4421d2012-03-01 19:16:31 +000025 break;
26 case SkPath::kQuad_Verb:
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000027 SkDebugf("path.quadTo(%3.6g, %3.6g, %3.6g, %3.6g);\n",
caryclark@google.comcd4421d2012-03-01 19:16:31 +000028 pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
29 break;
30 case SkPath::kCubic_Verb:
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000031 SkDebugf("path.cubicTo(%3.6g, %3.6g, %3.6g, %3.6g);\n",
caryclark@google.comcd4421d2012-03-01 19:16:31 +000032 pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY,
33 pts[3].fX, pts[3].fY);
34 break;
35 case SkPath::kClose_Verb:
36 SkDebugf("path.close();\n");
37 continue;
38 default:
39 SkDEBUGFAIL("bad verb");
40 return;
41 }
42 }
43}
44
45static bool pathsDrawTheSame(const SkPath& one, const SkPath& two) {
46 const SkRect& bounds1 = one.getBounds();
47 const SkRect& bounds2 = two.getBounds();
48 SkRect larger = bounds1;
49 larger.join(bounds2);
50 SkBitmap bits;
51 int bitWidth = SkScalarCeil(larger.width()) + 2;
52 int bitHeight = SkScalarCeil(larger.height()) + 2;
53 bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight);
54 bits.allocPixels();
55 SkCanvas canvas(bits);
56 canvas.drawColor(SK_ColorWHITE);
57 SkPaint paint;
58 canvas.save();
59 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
60 canvas.drawPath(one, paint);
61 canvas.restore();
62 canvas.save();
63 canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
64 canvas.drawPath(two, paint);
65 canvas.restore();
66 for (int y = 0; y < bitHeight; ++y) {
67 uint32_t* addr1 = bits.getAddr32(0, y);
68 uint32_t* addr2 = bits.getAddr32(bitWidth, y);
69 for (int x = 0; x < bitWidth; ++x) {
70 if (addr1[x] != addr2[x]) {
71 return false;
72 break;
73 }
74 }
75 }
76 return true;
77}
78
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000079void drawAsciiPaths(const SkPath& one, const SkPath& two,
caryclark@google.comcd4421d2012-03-01 19:16:31 +000080 bool drawPaths) {
81 if (!drawPaths) {
82 return;
83 }
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000084 if (gShowAsciiPaths) {
85 showPath(one, "one:");
86 showPath(two, "two:");
caryclark@google.comcd4421d2012-03-01 19:16:31 +000087 }
88 const SkRect& bounds1 = one.getBounds();
89 const SkRect& bounds2 = two.getBounds();
90 SkRect larger = bounds1;
91 larger.join(bounds2);
92 SkBitmap bits;
93 int bitWidth = SkScalarCeil(larger.width()) + 2;
94 int bitHeight = SkScalarCeil(larger.height()) + 2;
95 bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight);
96 bits.allocPixels();
97 SkCanvas canvas(bits);
98 canvas.drawColor(SK_ColorWHITE);
99 SkPaint paint;
100 canvas.save();
101 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
102 canvas.drawPath(one, paint);
103 canvas.restore();
104 canvas.save();
105 canvas.translate(-bounds2.fLeft + 1 + bitWidth, -bounds2.fTop + 1);
106 canvas.drawPath(two, paint);
107 canvas.restore();
108 char out[1024];
109 SkASSERT(bitWidth * 2 + 1 < (int) sizeof(out));
110 for (int y = 0; y < bitHeight; ++y) {
111 uint32_t* addr1 = bits.getAddr32(0, y);
112 int x;
113 char* outPtr = out;
114 for (x = 0; x < bitWidth; ++x) {
115 *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x';
116 }
117 *outPtr++ = '|';
118 for (x = bitWidth; x < bitWidth * 2; ++x) {
119 *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x';
120 }
121 *outPtr++ = '\0';
122 SkDebugf("%s\n", out);
123 }
124}
125
126static bool scaledDrawTheSame(const SkPath& one, const SkPath& two,
127 int a, int b, bool drawPaths) {
128 SkMatrix scale;
129 scale.reset();
130 scale.preScale(a * 1.21f, b * 1.11f);
131 SkPath scaledOne, scaledTwo;
132 one.transform(scale, &scaledOne);
133 two.transform(scale, &scaledTwo);
134 if (pathsDrawTheSame(scaledOne, scaledTwo)) {
135 return true;
136 }
137 drawAsciiPaths(scaledOne, scaledTwo, drawPaths);
138 return false;
139}
140
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000141bool comparePaths(const SkPath& one, const SkPath& two) {
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000142 if (pathsDrawTheSame(one, two)) {
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000143 return true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000144 }
145 drawAsciiPaths(one, two, gDrawAllAsciiPaths);
146 for (int x = 9; x <= 33; ++x) {
147 if (scaledDrawTheSame(one, two, x, x - (x >> 2), gDrawAllAsciiPaths)) {
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000148 return true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000149 }
150 }
151 if (!gDrawAllAsciiPaths) {
152 scaledDrawTheSame(one, two, 9, 7, gDrawLastAsciiPaths);
153 }
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000154 if (gComparePathsAssert) {
155 showPath(one);
156 showPath(two, "simplified:");
157 SkASSERT(0);
158 }
159 return false;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000160}
161
162// doesn't work yet
163void comparePathsTiny(const SkPath& one, const SkPath& two) {
164 const SkRect& bounds1 = one.getBounds();
165 const SkRect& bounds2 = two.getBounds();
166 SkRect larger = bounds1;
167 larger.join(bounds2);
168 SkBitmap bits;
169 int bitWidth = SkScalarCeil(larger.width()) + 2;
170 int bitHeight = SkScalarCeil(larger.height()) + 2;
171 bits.setConfig(SkBitmap::kA1_Config, bitWidth * 2, bitHeight);
172 bits.allocPixels();
173 SkCanvas canvas(bits);
174 canvas.drawColor(SK_ColorWHITE);
175 SkPaint paint;
176 canvas.save();
177 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
178 canvas.drawPath(one, paint);
179 canvas.restore();
180 canvas.save();
181 canvas.translate(-bounds2.fLeft + 1, -bounds2.fTop + 1);
182 canvas.drawPath(two, paint);
183 canvas.restore();
184 for (int y = 0; y < bitHeight; ++y) {
185 uint8_t* addr1 = bits.getAddr1(0, y);
186 uint8_t* addr2 = bits.getAddr1(bitWidth, y);
187 for (int x = 0; x < bits.rowBytes(); ++x) {
188 SkASSERT(addr1[x] == addr2[x]);
189 }
190 }
191}
192
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000193bool testSimplify(const SkPath& path, bool fill, SkPath& out) {
194 if (gShowPath) {
195 showPath(path);
196 }
197 simplify(path, fill, out);
198 return comparePaths(path, out);
199}