caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 1 | #include "EdgeWalker_Test.h" |
| 2 | #include "Intersection_Tests.h" |
| 3 | #include "SkBitmap.h" |
| 4 | #include "SkCanvas.h" |
| 5 | #include "SkPaint.h" |
caryclark@google.com | fb17342 | 2012-04-10 18:28:55 +0000 | [diff] [blame] | 6 | #include <algorithm> |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 7 | |
caryclark@google.com | 78e1713 | 2012-04-17 11:40:34 +0000 | [diff] [blame] | 8 | #undef SkASSERT |
| 9 | #define SkASSERT(cond) while (!(cond)) { sk_throw(); } |
| 10 | |
caryclark@google.com | 2e7f4c8 | 2012-03-20 21:11:59 +0000 | [diff] [blame] | 11 | static bool gShowPath = false; |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame] | 12 | static bool gComparePaths = true; |
caryclark@google.com | a3f05fa | 2012-06-01 17:44:28 +0000 | [diff] [blame^] | 13 | //static bool gDrawLastAsciiPaths = true; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 14 | static bool gDrawAllAsciiPaths = false; |
caryclark@google.com | 2e7f4c8 | 2012-03-20 21:11:59 +0000 | [diff] [blame] | 15 | static bool gShowAsciiPaths = false; |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 16 | static bool gComparePathsAssert = true; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 17 | |
caryclark@google.com | 2e7f4c8 | 2012-03-20 21:11:59 +0000 | [diff] [blame] | 18 | void showPath(const SkPath& path, const char* str) { |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 19 | SkDebugf("%s\n", !str ? "original:" : str); |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 20 | SkPath::Iter iter(path, true); |
| 21 | uint8_t verb; |
| 22 | SkPoint pts[4]; |
| 23 | while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { |
| 24 | switch (verb) { |
| 25 | case SkPath::kMove_Verb: |
caryclark@google.com | d88e089 | 2012-03-27 13:23:51 +0000 | [diff] [blame] | 26 | SkDebugf("path.moveTo(%1.9g, %1.9g);\n", pts[0].fX, pts[0].fY); |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 27 | continue; |
| 28 | case SkPath::kLine_Verb: |
caryclark@google.com | d88e089 | 2012-03-27 13:23:51 +0000 | [diff] [blame] | 29 | SkDebugf("path.lineTo(%1.9g, %1.9g);\n", pts[1].fX, pts[1].fY); |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 30 | break; |
| 31 | case SkPath::kQuad_Verb: |
caryclark@google.com | d88e089 | 2012-03-27 13:23:51 +0000 | [diff] [blame] | 32 | SkDebugf("path.quadTo(%1.9g, %1.9g, %1.9g, %1.9g);\n", |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 33 | pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY); |
| 34 | break; |
| 35 | case SkPath::kCubic_Verb: |
caryclark@google.com | d88e089 | 2012-03-27 13:23:51 +0000 | [diff] [blame] | 36 | SkDebugf("path.cubicTo(%1.9g, %1.9g, %1.9g, %1.9g);\n", |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 37 | pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY, |
| 38 | pts[3].fX, pts[3].fY); |
| 39 | break; |
| 40 | case SkPath::kClose_Verb: |
| 41 | SkDebugf("path.close();\n"); |
| 42 | continue; |
| 43 | default: |
| 44 | SkDEBUGFAIL("bad verb"); |
| 45 | return; |
| 46 | } |
| 47 | } |
| 48 | } |
| 49 | |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame] | 50 | static int pathsDrawTheSame(const SkPath& one, const SkPath& two, |
| 51 | SkBitmap& bits, SkCanvas* c) { |
| 52 | SkCanvas* canvasPtr = c; |
| 53 | if (!c) { |
| 54 | canvasPtr = new SkCanvas(bits); |
| 55 | } |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 56 | const SkRect& bounds1 = one.getBounds(); |
| 57 | const SkRect& bounds2 = two.getBounds(); |
| 58 | SkRect larger = bounds1; |
| 59 | larger.join(bounds2); |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 60 | int bitWidth = SkScalarCeil(larger.width()) + 2; |
| 61 | int bitHeight = SkScalarCeil(larger.height()) + 2; |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame] | 62 | if (bits.width() < bitWidth * 2 || bits.height() < bitHeight) { |
| 63 | if (bits.width() >= 200) { |
| 64 | SkDebugf("%s bitWidth=%d bitHeight=%d\n", __FUNCTION__, bitWidth, bitHeight); |
| 65 | } |
| 66 | bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight); |
| 67 | bits.allocPixels(); |
| 68 | canvasPtr->setBitmapDevice(bits); |
| 69 | } |
| 70 | SkCanvas& canvas = *canvasPtr; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 71 | canvas.drawColor(SK_ColorWHITE); |
| 72 | SkPaint paint; |
| 73 | canvas.save(); |
| 74 | canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1); |
| 75 | canvas.drawPath(one, paint); |
| 76 | canvas.restore(); |
| 77 | canvas.save(); |
| 78 | canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1); |
| 79 | canvas.drawPath(two, paint); |
| 80 | canvas.restore(); |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame] | 81 | int errors = 0; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 82 | for (int y = 0; y < bitHeight; ++y) { |
| 83 | uint32_t* addr1 = bits.getAddr32(0, y); |
| 84 | uint32_t* addr2 = bits.getAddr32(bitWidth, y); |
| 85 | for (int x = 0; x < bitWidth; ++x) { |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame] | 86 | errors += addr1[x] != addr2[x]; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 87 | } |
| 88 | } |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame] | 89 | if (!c) { |
| 90 | delete canvasPtr; |
| 91 | } |
| 92 | return errors; |
| 93 | } |
| 94 | |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 95 | bool drawAsciiPaths(const SkPath& one, const SkPath& two, |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 96 | bool drawPaths) { |
| 97 | if (!drawPaths) { |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 98 | return true; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 99 | } |
caryclark@google.com | 2e7f4c8 | 2012-03-20 21:11:59 +0000 | [diff] [blame] | 100 | if (gShowAsciiPaths) { |
| 101 | showPath(one, "one:"); |
| 102 | showPath(two, "two:"); |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 103 | } |
| 104 | const SkRect& bounds1 = one.getBounds(); |
| 105 | const SkRect& bounds2 = two.getBounds(); |
| 106 | SkRect larger = bounds1; |
| 107 | larger.join(bounds2); |
| 108 | SkBitmap bits; |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 109 | char out[256]; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 110 | int bitWidth = SkScalarCeil(larger.width()) + 2; |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 111 | if (bitWidth * 2 + 1 >= (int) sizeof(out)) { |
| 112 | return false; |
| 113 | } |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 114 | int bitHeight = SkScalarCeil(larger.height()) + 2; |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 115 | if (bitHeight >= (int) sizeof(out)) { |
| 116 | return false; |
| 117 | } |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 118 | bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight); |
| 119 | bits.allocPixels(); |
| 120 | SkCanvas canvas(bits); |
| 121 | canvas.drawColor(SK_ColorWHITE); |
| 122 | SkPaint paint; |
| 123 | canvas.save(); |
| 124 | canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1); |
| 125 | canvas.drawPath(one, paint); |
| 126 | canvas.restore(); |
| 127 | canvas.save(); |
caryclark@google.com | fb17342 | 2012-04-10 18:28:55 +0000 | [diff] [blame] | 128 | canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1); |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 129 | canvas.drawPath(two, paint); |
| 130 | canvas.restore(); |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 131 | for (int y = 0; y < bitHeight; ++y) { |
| 132 | uint32_t* addr1 = bits.getAddr32(0, y); |
| 133 | int x; |
| 134 | char* outPtr = out; |
| 135 | for (x = 0; x < bitWidth; ++x) { |
| 136 | *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x'; |
| 137 | } |
| 138 | *outPtr++ = '|'; |
| 139 | for (x = bitWidth; x < bitWidth * 2; ++x) { |
| 140 | *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x'; |
| 141 | } |
| 142 | *outPtr++ = '\0'; |
| 143 | SkDebugf("%s\n", out); |
| 144 | } |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 145 | return true; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 146 | } |
| 147 | |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame] | 148 | static int scaledDrawTheSame(const SkPath& one, const SkPath& two, |
caryclark@google.com | a3f05fa | 2012-06-01 17:44:28 +0000 | [diff] [blame^] | 149 | SkScalar a, SkScalar b, bool drawPaths, SkBitmap& bitmap, |
| 150 | SkCanvas* canvas) { |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 151 | SkMatrix scale; |
| 152 | scale.reset(); |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 153 | float aScale = 1.21f; |
| 154 | float bScale = 1.11f; |
| 155 | scale.preScale(a * aScale, b * bScale); |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 156 | SkPath scaledOne, scaledTwo; |
| 157 | one.transform(scale, &scaledOne); |
| 158 | two.transform(scale, &scaledTwo); |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame] | 159 | int errors = pathsDrawTheSame(scaledOne, scaledTwo, bitmap, canvas); |
| 160 | if (errors == 0) { |
| 161 | return 0; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 162 | } |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 163 | while (!drawAsciiPaths(scaledOne, scaledTwo, drawPaths)) { |
| 164 | scale.reset(); |
| 165 | aScale *= 0.5f; |
| 166 | bScale *= 0.5f; |
| 167 | scale.preScale(a * aScale, b * bScale); |
| 168 | one.transform(scale, &scaledOne); |
| 169 | two.transform(scale, &scaledTwo); |
| 170 | } |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame] | 171 | return errors; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 172 | } |
| 173 | |
caryclark@google.com | 78e1713 | 2012-04-17 11:40:34 +0000 | [diff] [blame] | 174 | static int max = 0; |
| 175 | |
caryclark@google.com | 1577e8f | 2012-05-22 17:01:14 +0000 | [diff] [blame] | 176 | int comparePaths(const SkPath& one, const SkPath& two, SkBitmap& bitmap, |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame] | 177 | SkCanvas* canvas) { |
| 178 | int errors = pathsDrawTheSame(one, two, bitmap, canvas); |
| 179 | if (errors == 0) { |
| 180 | return 0; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 181 | } |
| 182 | drawAsciiPaths(one, two, gDrawAllAsciiPaths); |
| 183 | for (int x = 9; x <= 33; ++x) { |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame] | 184 | errors = scaledDrawTheSame(one, two, x, x - (x >> 2), gDrawAllAsciiPaths, |
| 185 | bitmap, canvas); |
| 186 | if (errors == 0) { |
| 187 | return 0; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 188 | } |
| 189 | } |
| 190 | if (!gDrawAllAsciiPaths) { |
caryclark@google.com | fb17342 | 2012-04-10 18:28:55 +0000 | [diff] [blame] | 191 | const SkRect& bounds1 = one.getBounds(); |
| 192 | const SkRect& bounds2 = two.getBounds(); |
| 193 | SkRect larger = bounds1; |
| 194 | larger.join(bounds2); |
| 195 | SkScalar xScale = std::max(80.0f / larger.width(), 1.0f); |
| 196 | SkScalar yScale = std::max(60.0f / larger.height(), 1.0f); |
| 197 | errors = scaledDrawTheSame(one, two, xScale, yScale, false, bitmap, canvas); |
caryclark@google.com | 78e1713 | 2012-04-17 11:40:34 +0000 | [diff] [blame] | 198 | if (errors > 50) { |
caryclark@google.com | fb17342 | 2012-04-10 18:28:55 +0000 | [diff] [blame] | 199 | scaledDrawTheSame(one, two, xScale, yScale, true, bitmap, canvas); |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame] | 200 | } |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 201 | } |
caryclark@google.com | 78e1713 | 2012-04-17 11:40:34 +0000 | [diff] [blame] | 202 | if (errors > max) { |
| 203 | SkDebugf("\n%s errors=%d\n", __FUNCTION__, errors); |
| 204 | max = errors; |
| 205 | } |
| 206 | const int MAX_ERRORS = 100; |
| 207 | if (errors > MAX_ERRORS) SkDebugf("\n%s errors=%d\n", __FUNCTION__, errors); |
| 208 | if (errors > MAX_ERRORS && gComparePathsAssert) { |
caryclark@google.com | 2e7f4c8 | 2012-03-20 21:11:59 +0000 | [diff] [blame] | 209 | showPath(one); |
| 210 | showPath(two, "simplified:"); |
| 211 | SkASSERT(0); |
| 212 | } |
caryclark@google.com | 78e1713 | 2012-04-17 11:40:34 +0000 | [diff] [blame] | 213 | return errors > MAX_ERRORS ? errors : 0; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 214 | } |
| 215 | |
| 216 | // doesn't work yet |
| 217 | void comparePathsTiny(const SkPath& one, const SkPath& two) { |
| 218 | const SkRect& bounds1 = one.getBounds(); |
| 219 | const SkRect& bounds2 = two.getBounds(); |
| 220 | SkRect larger = bounds1; |
| 221 | larger.join(bounds2); |
| 222 | SkBitmap bits; |
| 223 | int bitWidth = SkScalarCeil(larger.width()) + 2; |
| 224 | int bitHeight = SkScalarCeil(larger.height()) + 2; |
| 225 | bits.setConfig(SkBitmap::kA1_Config, bitWidth * 2, bitHeight); |
| 226 | bits.allocPixels(); |
| 227 | SkCanvas canvas(bits); |
| 228 | canvas.drawColor(SK_ColorWHITE); |
| 229 | SkPaint paint; |
| 230 | canvas.save(); |
| 231 | canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1); |
| 232 | canvas.drawPath(one, paint); |
| 233 | canvas.restore(); |
| 234 | canvas.save(); |
| 235 | canvas.translate(-bounds2.fLeft + 1, -bounds2.fTop + 1); |
| 236 | canvas.drawPath(two, paint); |
| 237 | canvas.restore(); |
| 238 | for (int y = 0; y < bitHeight; ++y) { |
| 239 | uint8_t* addr1 = bits.getAddr1(0, y); |
| 240 | uint8_t* addr2 = bits.getAddr1(bitWidth, y); |
| 241 | for (int x = 0; x < bits.rowBytes(); ++x) { |
| 242 | SkASSERT(addr1[x] == addr2[x]); |
| 243 | } |
| 244 | } |
| 245 | } |
| 246 | |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame] | 247 | bool testSimplify(const SkPath& path, bool fill, SkPath& out, SkBitmap& bitmap, |
| 248 | SkCanvas* canvas) { |
caryclark@google.com | 2e7f4c8 | 2012-03-20 21:11:59 +0000 | [diff] [blame] | 249 | if (gShowPath) { |
| 250 | showPath(path); |
| 251 | } |
| 252 | simplify(path, fill, out); |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 253 | if (!gComparePaths) { |
| 254 | return true; |
| 255 | } |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame] | 256 | return comparePaths(path, out, bitmap, canvas) == 0; |
caryclark@google.com | 2e7f4c8 | 2012-03-20 21:11:59 +0000 | [diff] [blame] | 257 | } |
caryclark@google.com | 78e1713 | 2012-04-17 11:40:34 +0000 | [diff] [blame] | 258 | |
| 259 | State4::State4() { |
| 260 | bitmap.setConfig(SkBitmap::kARGB_8888_Config, 150 * 2, 100); |
| 261 | bitmap.allocPixels(); |
| 262 | canvas = new SkCanvas(bitmap); |
| 263 | } |
| 264 | |
| 265 | void createThread(State4* statePtr, void* (*test)(void* )) { |
| 266 | int threadError = pthread_create(&statePtr->threadID, NULL, test, |
| 267 | (void*) statePtr); |
| 268 | SkASSERT(!threadError); |
| 269 | } |
| 270 | |
| 271 | void waitForCompletion(State4 threadState[], int& threadIndex) { |
| 272 | for (int index = 0; index < threadIndex; ++index) { |
| 273 | pthread_join(threadState[index].threadID, NULL); |
| 274 | } |
| 275 | SkDebugf("."); |
| 276 | threadIndex = 0; |
| 277 | } |