1 /* 2 * Copyright 2011 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 "SkBitmap.h" 9 #include "SkCanvas.h" 10 #include "SkEdgeClipper.h" 11 #include "SkLineClipper.h" 12 #include "SkPath.h" 13 #include "Test.h" 14 15 static void test_hairclipping(skiatest::Reporter* reporter) { 16 SkBitmap bm; 17 bm.allocN32Pixels(4, 4); 18 bm.eraseColor(SK_ColorWHITE); 19 20 SkPaint paint; 21 paint.setAntiAlias(true); 22 23 SkCanvas canvas(bm); 24 canvas.clipRect(SkRect::MakeWH(SkIntToScalar(4), SkIntToScalar(2))); 25 canvas.drawLine(1.5f, 1.5f, 26 3.5f, 3.5f, paint); 27 28 /** 29 * We had a bug where we misinterpreted the bottom of the clip, and 30 * would draw another pixel (to the right in this case) on the same 31 * last scanline. i.e. we would draw to [2,1], even though this hairline 32 * should just draw to [1,1], [2,2], [3,3] modulo the clip. 33 * 34 * The result of this entire draw should be that we only draw to [1,1] 35 * 36 * Fixed in rev. 3366 37 */ 38 for (int y = 0; y < 4; ++y) { 39 for (int x = 0; x < 4; ++x) { 40 bool nonWhite = (1 == y) && (1 == x); 41 SkPMColor c = *bm.getAddr32(x, y); 42 if (nonWhite) { 43 REPORTER_ASSERT(reporter, 0xFFFFFFFF != c); 44 } else { 45 REPORTER_ASSERT(reporter, 0xFFFFFFFF == c); 46 } 47 } 48 } 49 } 50 51 static void test_edgeclipper() { 52 SkEdgeClipper clipper(false); 53 54 const SkPoint pts[] = { 55 { 3.0995476e+010f, 42.929779f }, 56 { -3.0995163e+010f, 51.050385f }, 57 { -3.0995157e+010f, 51.050392f }, 58 { -3.0995134e+010f, 51.050400f }, 59 }; 60 61 const SkRect clip = { 0, 0, SkIntToScalar(300), SkIntToScalar(200) }; 62 63 // this should not assert, even though our choppers do a poor numerical 64 // job when computing their t values. 65 // http://code.google.com/p/skia/issues/detail?id=444 66 clipper.clipCubic(pts, clip); 67 } 68 69 static void test_intersectline(skiatest::Reporter* reporter) { 70 static const SkScalar L = 0; 71 static const SkScalar T = 0; 72 static const SkScalar R = SkIntToScalar(100); 73 static const SkScalar B = SkIntToScalar(100); 74 static const SkScalar CX = SkScalarHalf(L + R); 75 static const SkScalar CY = SkScalarHalf(T + B); 76 static const SkRect gR = { L, T, R, B }; 77 78 size_t i; 79 SkPoint dst[2]; 80 81 static const SkPoint gEmpty[] = { 82 // sides 83 { L, CY }, { L - 10, CY }, 84 { R, CY }, { R + 10, CY }, 85 { CX, T }, { CX, T - 10 }, 86 { CX, B }, { CX, B + 10 }, 87 // corners 88 { L, T }, { L - 10, T - 10 }, 89 { L, B }, { L - 10, B + 10 }, 90 { R, T }, { R + 10, T - 10 }, 91 { R, B }, { R + 10, B + 10 }, 92 }; 93 for (i = 0; i < SK_ARRAY_COUNT(gEmpty); i += 2) { 94 bool valid = SkLineClipper::IntersectLine(&gEmpty[i], gR, dst); 95 if (valid) { 96 SkDebugf("----- [%d] %g %g -> %g %g\n", i/2, dst[0].fX, dst[0].fY, dst[1].fX, dst[1].fY); 97 } 98 REPORTER_ASSERT(reporter, !valid); 99 } 100 101 static const SkPoint gFull[] = { 102 // diagonals, chords 103 { L, T }, { R, B }, 104 { L, B }, { R, T }, 105 { CX, T }, { CX, B }, 106 { L, CY }, { R, CY }, 107 { CX, T }, { R, CY }, 108 { CX, T }, { L, CY }, 109 { L, CY }, { CX, B }, 110 { R, CY }, { CX, B }, 111 // edges 112 { L, T }, { L, B }, 113 { R, T }, { R, B }, 114 { L, T }, { R, T }, 115 { L, B }, { R, B }, 116 }; 117 for (i = 0; i < SK_ARRAY_COUNT(gFull); i += 2) { 118 bool valid = SkLineClipper::IntersectLine(&gFull[i], gR, dst); 119 if (!valid || memcmp(&gFull[i], dst, sizeof(dst))) { 120 SkDebugf("++++ [%d] %g %g -> %g %g\n", i/2, dst[0].fX, dst[0].fY, dst[1].fX, dst[1].fY); 121 } 122 REPORTER_ASSERT(reporter, valid && !memcmp(&gFull[i], dst, sizeof(dst))); 123 } 124 125 static const SkPoint gPartial[] = { 126 { L - 10, CY }, { CX, CY }, { L, CY }, { CX, CY }, 127 { CX, T - 10 }, { CX, CY }, { CX, T }, { CX, CY }, 128 { R + 10, CY }, { CX, CY }, { R, CY }, { CX, CY }, 129 { CX, B + 10 }, { CX, CY }, { CX, B }, { CX, CY }, 130 // extended edges 131 { L, T - 10 }, { L, B + 10 }, { L, T }, { L, B }, 132 { R, T - 10 }, { R, B + 10 }, { R, T }, { R, B }, 133 { L - 10, T }, { R + 10, T }, { L, T }, { R, T }, 134 { L - 10, B }, { R + 10, B }, { L, B }, { R, B }, 135 }; 136 for (i = 0; i < SK_ARRAY_COUNT(gPartial); i += 4) { 137 bool valid = SkLineClipper::IntersectLine(&gPartial[i], gR, dst); 138 if (!valid || memcmp(&gPartial[i+2], dst, sizeof(dst))) { 139 SkDebugf("++++ [%d] %g %g -> %g %g\n", i/2, dst[0].fX, dst[0].fY, dst[1].fX, dst[1].fY); 140 } 141 REPORTER_ASSERT(reporter, valid && 142 !memcmp(&gPartial[i+2], dst, sizeof(dst))); 143 } 144 145 } 146 147 DEF_TEST(Clipper, reporter) { 148 test_intersectline(reporter); 149 test_edgeclipper(); 150 test_hairclipping(reporter); 151 } 152