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" |
| 6 | |
caryclark@google.com | 2e7f4c8 | 2012-03-20 21:11:59 +0000 | [diff] [blame] | 7 | static bool gShowPath = false; |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame^] | 8 | static bool gComparePaths = true; |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 9 | static bool gDrawLastAsciiPaths = true; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 10 | static bool gDrawAllAsciiPaths = false; |
caryclark@google.com | 2e7f4c8 | 2012-03-20 21:11:59 +0000 | [diff] [blame] | 11 | static bool gShowAsciiPaths = false; |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 12 | static bool gComparePathsAssert = true; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 13 | |
caryclark@google.com | 2e7f4c8 | 2012-03-20 21:11:59 +0000 | [diff] [blame] | 14 | void showPath(const SkPath& path, const char* str) { |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 15 | SkDebugf("%s\n", !str ? "original:" : str); |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 16 | 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.com | d88e089 | 2012-03-27 13:23:51 +0000 | [diff] [blame] | 22 | 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] | 23 | continue; |
| 24 | case SkPath::kLine_Verb: |
caryclark@google.com | d88e089 | 2012-03-27 13:23:51 +0000 | [diff] [blame] | 25 | 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] | 26 | break; |
| 27 | case SkPath::kQuad_Verb: |
caryclark@google.com | d88e089 | 2012-03-27 13:23:51 +0000 | [diff] [blame] | 28 | 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] | 29 | pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY); |
| 30 | break; |
| 31 | case SkPath::kCubic_Verb: |
caryclark@google.com | d88e089 | 2012-03-27 13:23:51 +0000 | [diff] [blame] | 32 | 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] | 33 | 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 | |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame^] | 46 | static int pathsDrawTheSame(const SkPath& one, const SkPath& two, |
| 47 | SkBitmap& bits, SkCanvas* c) { |
| 48 | SkCanvas* canvasPtr = c; |
| 49 | if (!c) { |
| 50 | canvasPtr = new SkCanvas(bits); |
| 51 | } |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 52 | const SkRect& bounds1 = one.getBounds(); |
| 53 | const SkRect& bounds2 = two.getBounds(); |
| 54 | SkRect larger = bounds1; |
| 55 | larger.join(bounds2); |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 56 | int bitWidth = SkScalarCeil(larger.width()) + 2; |
| 57 | int bitHeight = SkScalarCeil(larger.height()) + 2; |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame^] | 58 | if (bits.width() < bitWidth * 2 || bits.height() < bitHeight) { |
| 59 | if (bits.width() >= 200) { |
| 60 | SkDebugf("%s bitWidth=%d bitHeight=%d\n", __FUNCTION__, bitWidth, bitHeight); |
| 61 | } |
| 62 | bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight); |
| 63 | bits.allocPixels(); |
| 64 | canvasPtr->setBitmapDevice(bits); |
| 65 | } |
| 66 | SkCanvas& canvas = *canvasPtr; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 67 | canvas.drawColor(SK_ColorWHITE); |
| 68 | SkPaint paint; |
| 69 | canvas.save(); |
| 70 | canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1); |
| 71 | canvas.drawPath(one, paint); |
| 72 | canvas.restore(); |
| 73 | canvas.save(); |
| 74 | canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1); |
| 75 | canvas.drawPath(two, paint); |
| 76 | canvas.restore(); |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame^] | 77 | int errors = 0; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 78 | for (int y = 0; y < bitHeight; ++y) { |
| 79 | uint32_t* addr1 = bits.getAddr32(0, y); |
| 80 | uint32_t* addr2 = bits.getAddr32(bitWidth, y); |
| 81 | for (int x = 0; x < bitWidth; ++x) { |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame^] | 82 | errors += addr1[x] != addr2[x]; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 83 | } |
| 84 | } |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame^] | 85 | if (!c) { |
| 86 | delete canvasPtr; |
| 87 | } |
| 88 | return errors; |
| 89 | } |
| 90 | |
| 91 | void bitmapInit(SkBitmap& bits) { |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 92 | } |
| 93 | |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 94 | bool drawAsciiPaths(const SkPath& one, const SkPath& two, |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 95 | bool drawPaths) { |
| 96 | if (!drawPaths) { |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 97 | return true; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 98 | } |
caryclark@google.com | 2e7f4c8 | 2012-03-20 21:11:59 +0000 | [diff] [blame] | 99 | if (gShowAsciiPaths) { |
| 100 | showPath(one, "one:"); |
| 101 | showPath(two, "two:"); |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 102 | } |
| 103 | const SkRect& bounds1 = one.getBounds(); |
| 104 | const SkRect& bounds2 = two.getBounds(); |
| 105 | SkRect larger = bounds1; |
| 106 | larger.join(bounds2); |
| 107 | SkBitmap bits; |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 108 | char out[256]; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 109 | int bitWidth = SkScalarCeil(larger.width()) + 2; |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 110 | if (bitWidth * 2 + 1 >= (int) sizeof(out)) { |
| 111 | return false; |
| 112 | } |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 113 | int bitHeight = SkScalarCeil(larger.height()) + 2; |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 114 | if (bitHeight >= (int) sizeof(out)) { |
| 115 | return false; |
| 116 | } |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 117 | bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight); |
| 118 | bits.allocPixels(); |
| 119 | SkCanvas canvas(bits); |
| 120 | canvas.drawColor(SK_ColorWHITE); |
| 121 | SkPaint paint; |
| 122 | canvas.save(); |
| 123 | canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1); |
| 124 | canvas.drawPath(one, paint); |
| 125 | canvas.restore(); |
| 126 | canvas.save(); |
| 127 | canvas.translate(-bounds2.fLeft + 1 + bitWidth, -bounds2.fTop + 1); |
| 128 | canvas.drawPath(two, paint); |
| 129 | canvas.restore(); |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 130 | for (int y = 0; y < bitHeight; ++y) { |
| 131 | uint32_t* addr1 = bits.getAddr32(0, y); |
| 132 | int x; |
| 133 | char* outPtr = out; |
| 134 | for (x = 0; x < bitWidth; ++x) { |
| 135 | *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x'; |
| 136 | } |
| 137 | *outPtr++ = '|'; |
| 138 | for (x = bitWidth; x < bitWidth * 2; ++x) { |
| 139 | *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x'; |
| 140 | } |
| 141 | *outPtr++ = '\0'; |
| 142 | SkDebugf("%s\n", out); |
| 143 | } |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 144 | return true; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 145 | } |
| 146 | |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame^] | 147 | static int scaledDrawTheSame(const SkPath& one, const SkPath& two, |
| 148 | int a, int b, bool drawPaths, SkBitmap& bitmap, SkCanvas* canvas) { |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 149 | SkMatrix scale; |
| 150 | scale.reset(); |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 151 | float aScale = 1.21f; |
| 152 | float bScale = 1.11f; |
| 153 | scale.preScale(a * aScale, b * bScale); |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 154 | SkPath scaledOne, scaledTwo; |
| 155 | one.transform(scale, &scaledOne); |
| 156 | two.transform(scale, &scaledTwo); |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame^] | 157 | int errors = pathsDrawTheSame(scaledOne, scaledTwo, bitmap, canvas); |
| 158 | if (errors == 0) { |
| 159 | return 0; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 160 | } |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 161 | while (!drawAsciiPaths(scaledOne, scaledTwo, drawPaths)) { |
| 162 | scale.reset(); |
| 163 | aScale *= 0.5f; |
| 164 | bScale *= 0.5f; |
| 165 | scale.preScale(a * aScale, b * bScale); |
| 166 | one.transform(scale, &scaledOne); |
| 167 | two.transform(scale, &scaledTwo); |
| 168 | } |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame^] | 169 | return errors; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 170 | } |
| 171 | |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame^] | 172 | static int comparePaths(const SkPath& one, const SkPath& two, SkBitmap& bitmap, |
| 173 | SkCanvas* canvas) { |
| 174 | int errors = pathsDrawTheSame(one, two, bitmap, canvas); |
| 175 | if (errors == 0) { |
| 176 | return 0; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 177 | } |
| 178 | drawAsciiPaths(one, two, gDrawAllAsciiPaths); |
| 179 | for (int x = 9; x <= 33; ++x) { |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame^] | 180 | errors = scaledDrawTheSame(one, two, x, x - (x >> 2), gDrawAllAsciiPaths, |
| 181 | bitmap, canvas); |
| 182 | if (errors == 0) { |
| 183 | return 0; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 184 | } |
| 185 | } |
| 186 | if (!gDrawAllAsciiPaths) { |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame^] | 187 | errors = scaledDrawTheSame(one, two, 9, 7, false, bitmap, canvas); |
| 188 | if (errors > 4) { |
| 189 | scaledDrawTheSame(one, two, 9, 7, true, bitmap, canvas); |
| 190 | } |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 191 | } |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame^] | 192 | if (errors > 0) SkDebugf("\n%s errors=%d\n", __FUNCTION__, errors); |
| 193 | if (errors > 4 && gComparePathsAssert) { |
caryclark@google.com | 2e7f4c8 | 2012-03-20 21:11:59 +0000 | [diff] [blame] | 194 | showPath(one); |
| 195 | showPath(two, "simplified:"); |
| 196 | SkASSERT(0); |
| 197 | } |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame^] | 198 | return errors; |
caryclark@google.com | cd4421d | 2012-03-01 19:16:31 +0000 | [diff] [blame] | 199 | } |
| 200 | |
| 201 | // doesn't work yet |
| 202 | void comparePathsTiny(const SkPath& one, const SkPath& two) { |
| 203 | const SkRect& bounds1 = one.getBounds(); |
| 204 | const SkRect& bounds2 = two.getBounds(); |
| 205 | SkRect larger = bounds1; |
| 206 | larger.join(bounds2); |
| 207 | SkBitmap bits; |
| 208 | int bitWidth = SkScalarCeil(larger.width()) + 2; |
| 209 | int bitHeight = SkScalarCeil(larger.height()) + 2; |
| 210 | bits.setConfig(SkBitmap::kA1_Config, bitWidth * 2, bitHeight); |
| 211 | bits.allocPixels(); |
| 212 | SkCanvas canvas(bits); |
| 213 | canvas.drawColor(SK_ColorWHITE); |
| 214 | SkPaint paint; |
| 215 | canvas.save(); |
| 216 | canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1); |
| 217 | canvas.drawPath(one, paint); |
| 218 | canvas.restore(); |
| 219 | canvas.save(); |
| 220 | canvas.translate(-bounds2.fLeft + 1, -bounds2.fTop + 1); |
| 221 | canvas.drawPath(two, paint); |
| 222 | canvas.restore(); |
| 223 | for (int y = 0; y < bitHeight; ++y) { |
| 224 | uint8_t* addr1 = bits.getAddr1(0, y); |
| 225 | uint8_t* addr2 = bits.getAddr1(bitWidth, y); |
| 226 | for (int x = 0; x < bits.rowBytes(); ++x) { |
| 227 | SkASSERT(addr1[x] == addr2[x]); |
| 228 | } |
| 229 | } |
| 230 | } |
| 231 | |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame^] | 232 | bool testSimplify(const SkPath& path, bool fill, SkPath& out, SkBitmap& bitmap, |
| 233 | SkCanvas* canvas) { |
caryclark@google.com | 2e7f4c8 | 2012-03-20 21:11:59 +0000 | [diff] [blame] | 234 | if (gShowPath) { |
| 235 | showPath(path); |
| 236 | } |
| 237 | simplify(path, fill, out); |
caryclark@google.com | 752b60e | 2012-03-22 21:11:17 +0000 | [diff] [blame] | 238 | if (!gComparePaths) { |
| 239 | return true; |
| 240 | } |
caryclark@google.com | 198e054 | 2012-03-30 18:47:02 +0000 | [diff] [blame^] | 241 | return comparePaths(path, out, bitmap, canvas) == 0; |
caryclark@google.com | 2e7f4c8 | 2012-03-20 21:11:59 +0000 | [diff] [blame] | 242 | } |