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 "SkData.h" 11 #include "SkDiscardableMemoryPool.h" 12 #include "SkImageGenerator.h" 13 #include "SkMatrixUtils.h" 14 #include "SkPaint.h" 15 #include "SkPath.h" 16 #include "SkPixelRef.h" 17 #include "SkRandom.h" 18 #include "SkShader.h" 19 #include "SkSurface.h" 20 #include "Test.h" 21 22 /////////////////////////////////////////////////////////////////////////////// 23 24 static void rand_matrix(SkMatrix* mat, SkRandom& rand, unsigned mask) { 25 mat->setIdentity(); 26 if (mask & SkMatrix::kTranslate_Mask) { 27 mat->postTranslate(rand.nextSScalar1(), rand.nextSScalar1()); 28 } 29 if (mask & SkMatrix::kScale_Mask) { 30 mat->postScale(rand.nextSScalar1(), rand.nextSScalar1()); 31 } 32 if (mask & SkMatrix::kAffine_Mask) { 33 mat->postRotate(rand.nextSScalar1() * 360); 34 } 35 if (mask & SkMatrix::kPerspective_Mask) { 36 mat->setPerspX(rand.nextSScalar1()); 37 mat->setPerspY(rand.nextSScalar1()); 38 } 39 } 40 41 static void rand_size(SkISize* size, SkRandom& rand) { 42 size->set(rand.nextU() & 0xFFFF, rand.nextU() & 0xFFFF); 43 } 44 45 static void test_treatAsSprite(skiatest::Reporter* reporter) { 46 47 SkMatrix mat; 48 SkISize size; 49 SkRandom rand; 50 51 SkPaint noaaPaint; 52 SkPaint aaPaint; 53 aaPaint.setAntiAlias(true); 54 55 // assert: translate-only no-aa can always be treated as sprite 56 for (int i = 0; i < 1000; ++i) { 57 rand_matrix(&mat, rand, SkMatrix::kTranslate_Mask); 58 for (int j = 0; j < 1000; ++j) { 59 rand_size(&size, rand); 60 REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, noaaPaint)); 61 } 62 } 63 64 // assert: rotate/perspect is never treated as sprite 65 for (int i = 0; i < 1000; ++i) { 66 rand_matrix(&mat, rand, SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask); 67 for (int j = 0; j < 1000; ++j) { 68 rand_size(&size, rand); 69 REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, noaaPaint)); 70 REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, aaPaint)); 71 } 72 } 73 74 size.set(500, 600); 75 76 const SkScalar tooMuchSubpixel = 100.1f; 77 mat.setTranslate(tooMuchSubpixel, 0); 78 REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, aaPaint)); 79 mat.setTranslate(0, tooMuchSubpixel); 80 REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, aaPaint)); 81 82 const SkScalar tinySubPixel = 100.02f; 83 mat.setTranslate(tinySubPixel, 0); 84 REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, aaPaint)); 85 mat.setTranslate(0, tinySubPixel); 86 REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, aaPaint)); 87 88 const SkScalar twoThirds = SK_Scalar1 * 2 / 3; 89 const SkScalar bigScale = (size.width() + twoThirds) / size.width(); 90 mat.setScale(bigScale, bigScale); 91 REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, noaaPaint)); 92 REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, aaPaint)); 93 94 const SkScalar oneThird = SK_Scalar1 / 3; 95 const SkScalar smallScale = (size.width() + oneThird) / size.width(); 96 mat.setScale(smallScale, smallScale); 97 REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, noaaPaint)); 98 REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, aaPaint)); 99 100 const SkScalar oneFortyth = SK_Scalar1 / 40; 101 const SkScalar tinyScale = (size.width() + oneFortyth) / size.width(); 102 mat.setScale(tinyScale, tinyScale); 103 REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, noaaPaint)); 104 REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, aaPaint)); 105 } 106 107 static void assert_ifDrawnTo(skiatest::Reporter* reporter, 108 const SkBitmap& bm, bool shouldBeDrawn) { 109 for (int y = 0; y < bm.height(); ++y) { 110 for (int x = 0; x < bm.width(); ++x) { 111 if (shouldBeDrawn) { 112 if (SK_ColorTRANSPARENT == *bm.getAddr32(x, y)) { 113 REPORTER_ASSERT(reporter, false); 114 return; 115 } 116 } else { 117 // should not be drawn 118 if (SK_ColorTRANSPARENT != *bm.getAddr32(x, y)) { 119 REPORTER_ASSERT(reporter, false); 120 return; 121 } 122 } 123 } 124 } 125 } 126 127 static void test_wacky_bitmapshader(skiatest::Reporter* reporter, 128 int width, int height, bool shouldBeDrawn) { 129 SkBitmap dev; 130 dev.allocN32Pixels(0x56F, 0x4f6); 131 dev.eraseColor(SK_ColorTRANSPARENT); // necessary, so we know if we draw to it 132 133 SkMatrix matrix; 134 135 SkCanvas c(dev); 136 matrix.setAll(-119.34097f, 137 -43.436558f, 138 93489.945f, 139 43.436558f, 140 -119.34097f, 141 123.98426f, 142 0, 0, SK_Scalar1); 143 c.concat(matrix); 144 145 SkBitmap bm; 146 if (bm.tryAllocN32Pixels(width, height)) { 147 bm.eraseColor(SK_ColorRED); 148 } else { 149 shouldBeDrawn = false; 150 } 151 152 matrix.setAll(0.0078740157f, 153 0, 154 SkIntToScalar(249), 155 0, 156 0.0078740157f, 157 SkIntToScalar(239), 158 0, 0, SK_Scalar1); 159 SkPaint paint; 160 paint.setShader(SkShader::MakeBitmapShader(bm, SkShader::kRepeat_TileMode, 161 SkShader::kRepeat_TileMode, &matrix)); 162 163 SkRect r = SkRect::MakeXYWH(681, 239, 695, 253); 164 c.drawRect(r, paint); 165 166 assert_ifDrawnTo(reporter, dev, shouldBeDrawn); 167 } 168 169 /* 170 * Original bug was asserting that the matrix-proc had generated a (Y) value 171 * that was out of range. This led (in the release build) to the sampler-proc 172 * reading memory out-of-bounds of the original bitmap. 173 * 174 * We were numerically overflowing our 16bit coordinates that we communicate 175 * between these two procs. The fixes was in two parts: 176 * 177 * 1. Just don't draw bitmaps larger than 64K-1 in width or height, since we 178 * can't represent those coordinates in our transport format (yet). 179 * 2. Perform an unsigned shift during the calculation, so we don't get 180 * sign-extension bleed when packing the two values (X,Y) into our 32bit 181 * slot. 182 * 183 * This tests exercises the original setup, plus 2 more to ensure that we can, 184 * in fact, handle bitmaps at 64K-1 (assuming we don't exceed the total 185 * memory allocation limit). 186 */ 187 static void test_giantrepeat_crbug118018(skiatest::Reporter* reporter) { 188 static const struct { 189 int fWidth; 190 int fHeight; 191 bool fExpectedToDraw; 192 } gTests[] = { 193 { 0x1b294, 0x7f, false }, // crbug 118018 (width exceeds 64K) 194 { 0xFFFF, 0x7f, true }, // should draw, test max width 195 { 0x7f, 0xFFFF, true }, // should draw, test max height 196 }; 197 198 for (size_t i = 0; i < SK_ARRAY_COUNT(gTests); ++i) { 199 test_wacky_bitmapshader(reporter, 200 gTests[i].fWidth, gTests[i].fHeight, 201 gTests[i].fExpectedToDraw); 202 } 203 } 204 205 /////////////////////////////////////////////////////////////////////////////// 206 207 static void test_nan_antihair() { 208 SkBitmap bm; 209 bm.allocN32Pixels(20, 20); 210 211 SkCanvas canvas(bm); 212 213 SkPath path; 214 path.moveTo(0, 0); 215 path.lineTo(10, SK_ScalarNaN); 216 217 SkPaint paint; 218 paint.setAntiAlias(true); 219 paint.setStyle(SkPaint::kStroke_Style); 220 221 // before our fix to SkScan_Antihair.cpp to check for integral NaN (0x800...) 222 // this would trigger an assert/crash. 223 // 224 // see rev. 3558 225 canvas.drawPath(path, paint); 226 } 227 228 static bool check_for_all_zeros(const SkBitmap& bm) { 229 size_t count = bm.width() * bm.bytesPerPixel(); 230 for (int y = 0; y < bm.height(); y++) { 231 const uint8_t* ptr = reinterpret_cast<const uint8_t*>(bm.getAddr(0, y)); 232 for (size_t i = 0; i < count; i++) { 233 if (ptr[i]) { 234 return false; 235 } 236 } 237 } 238 return true; 239 } 240 241 static const int gWidth = 256; 242 static const int gHeight = 256; 243 244 static void create(SkBitmap* bm, SkColor color) { 245 bm->allocN32Pixels(gWidth, gHeight); 246 bm->eraseColor(color); 247 } 248 249 DEF_TEST(DrawBitmapRect, reporter) { 250 SkBitmap src, dst; 251 252 create(&src, 0xFFFFFFFF); 253 create(&dst, 0); 254 255 SkCanvas canvas(dst); 256 257 SkIRect srcR = { gWidth, 0, gWidth + 16, 16 }; 258 SkRect dstR = { 0, 0, SkIntToScalar(16), SkIntToScalar(16) }; 259 260 canvas.drawBitmapRect(src, srcR, dstR, nullptr); 261 262 // ensure that we draw nothing if srcR does not intersect the bitmap 263 REPORTER_ASSERT(reporter, check_for_all_zeros(dst)); 264 265 test_nan_antihair(); 266 test_giantrepeat_crbug118018(reporter); 267 268 test_treatAsSprite(reporter); 269 } 270