1 /* 2 * Copyright 2013 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 "SkColor.h" 10 #include "SkImageInfo.h" 11 #include "SkMallocPixelRef.h" 12 #include "SkPixelRef.h" 13 #include "SkPixmap.h" 14 #include "SkRandom.h" 15 #include "SkRefCnt.h" 16 #include "SkTypes.h" 17 #include "Test.h" 18 #include "sk_tool_utils.h" 19 20 static void test_peekpixels(skiatest::Reporter* reporter) { 21 const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10); 22 23 SkPixmap pmap; 24 SkBitmap bm; 25 26 // empty should return false 27 REPORTER_ASSERT(reporter, !bm.peekPixels(nullptr)); 28 REPORTER_ASSERT(reporter, !bm.peekPixels(&pmap)); 29 30 // no pixels should return false 31 bm.setInfo(SkImageInfo::MakeN32Premul(10, 10)); 32 REPORTER_ASSERT(reporter, !bm.peekPixels(nullptr)); 33 REPORTER_ASSERT(reporter, !bm.peekPixels(&pmap)); 34 35 // real pixels should return true 36 bm.allocPixels(info); 37 REPORTER_ASSERT(reporter, bm.peekPixels(nullptr)); 38 REPORTER_ASSERT(reporter, bm.peekPixels(&pmap)); 39 REPORTER_ASSERT(reporter, pmap.info() == bm.info()); 40 REPORTER_ASSERT(reporter, pmap.addr() == bm.getPixels()); 41 REPORTER_ASSERT(reporter, pmap.rowBytes() == bm.rowBytes()); 42 } 43 44 // https://code.google.com/p/chromium/issues/detail?id=446164 45 static void test_bigalloc(skiatest::Reporter* reporter) { 46 const int width = 0x40000001; 47 const int height = 0x00000096; 48 const SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); 49 50 SkBitmap bm; 51 REPORTER_ASSERT(reporter, !bm.tryAllocPixels(info)); 52 53 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(info, info.minRowBytes()); 54 REPORTER_ASSERT(reporter, !pr); 55 } 56 57 static void test_allocpixels(skiatest::Reporter* reporter) { 58 const int width = 10; 59 const int height = 10; 60 const SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); 61 const size_t explicitRowBytes = info.minRowBytes() + 24; 62 63 SkBitmap bm; 64 bm.setInfo(info); 65 REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes()); 66 bm.allocPixels(); 67 REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes()); 68 bm.reset(); 69 bm.allocPixels(info); 70 REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes()); 71 72 bm.setInfo(info, explicitRowBytes); 73 REPORTER_ASSERT(reporter, explicitRowBytes == bm.rowBytes()); 74 bm.allocPixels(); 75 REPORTER_ASSERT(reporter, explicitRowBytes == bm.rowBytes()); 76 bm.reset(); 77 bm.allocPixels(info, explicitRowBytes); 78 REPORTER_ASSERT(reporter, explicitRowBytes == bm.rowBytes()); 79 80 bm.reset(); 81 bm.setInfo(info, 0); 82 REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes()); 83 bm.reset(); 84 bm.allocPixels(info, 0); 85 REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes()); 86 87 bm.reset(); 88 bool success = bm.setInfo(info, info.minRowBytes() - 1); // invalid for 32bit 89 REPORTER_ASSERT(reporter, !success); 90 REPORTER_ASSERT(reporter, bm.isNull()); 91 } 92 93 static void test_bigwidth(skiatest::Reporter* reporter) { 94 SkBitmap bm; 95 int width = 1 << 29; // *4 will be the high-bit of 32bit int 96 97 SkImageInfo info = SkImageInfo::MakeA8(width, 1); 98 REPORTER_ASSERT(reporter, bm.setInfo(info)); 99 REPORTER_ASSERT(reporter, bm.setInfo(info.makeColorType(kRGB_565_SkColorType))); 100 101 // for a 4-byte config, this width will compute a rowbytes of 0x80000000, 102 // which does not fit in a int32_t. setConfig should detect this, and fail. 103 104 // TODO: perhaps skia can relax this, and only require that rowBytes fit 105 // in a uint32_t (or larger), but for now this is the constraint. 106 107 REPORTER_ASSERT(reporter, !bm.setInfo(info.makeColorType(kN32_SkColorType))); 108 } 109 110 /** 111 * This test contains basic sanity checks concerning bitmaps. 112 */ 113 DEF_TEST(Bitmap, reporter) { 114 // Zero-sized bitmaps are allowed 115 for (int width = 0; width < 2; ++width) { 116 for (int height = 0; height < 2; ++height) { 117 SkBitmap bm; 118 bool setConf = bm.setInfo(SkImageInfo::MakeN32Premul(width, height)); 119 REPORTER_ASSERT(reporter, setConf); 120 if (setConf) { 121 bm.allocPixels(); 122 } 123 REPORTER_ASSERT(reporter, SkToBool(width & height) != bm.empty()); 124 } 125 } 126 127 test_bigwidth(reporter); 128 test_allocpixels(reporter); 129 test_bigalloc(reporter); 130 test_peekpixels(reporter); 131 } 132 133 /** 134 * This test checks that getColor works for both swizzles. 135 */ 136 DEF_TEST(Bitmap_getColor_Swizzle, r) { 137 SkBitmap source; 138 source.allocN32Pixels(1,1); 139 source.eraseColor(SK_ColorRED); 140 SkColorType colorTypes[] = { 141 kRGBA_8888_SkColorType, 142 kBGRA_8888_SkColorType, 143 }; 144 for (SkColorType ct : colorTypes) { 145 SkBitmap copy; 146 if (!sk_tool_utils::copy_to(©, ct, source)) { 147 ERRORF(r, "SkBitmap::copy failed %d", (int)ct); 148 continue; 149 } 150 REPORTER_ASSERT(r, source.getColor(0, 0) == copy.getColor(0, 0)); 151 } 152 } 153 154 static void test_erasecolor_premul(skiatest::Reporter* reporter, SkColorType ct, SkColor input, 155 SkColor expected) { 156 SkBitmap bm; 157 bm.allocPixels(SkImageInfo::Make(1, 1, ct, kPremul_SkAlphaType)); 158 bm.eraseColor(input); 159 INFOF(reporter, "expected: %x actual: %x\n", expected, bm.getColor(0, 0)); 160 REPORTER_ASSERT(reporter, bm.getColor(0, 0) == expected); 161 } 162 163 /** 164 * This test checks that eraseColor premultiplies the color correctly. 165 */ 166 DEF_TEST(Bitmap_eraseColor_Premul, r) { 167 SkColor color = 0x80FF0080; 168 test_erasecolor_premul(r, kAlpha_8_SkColorType, color, 0x80000000); 169 test_erasecolor_premul(r, kRGB_565_SkColorType, color, 0xFF840042); 170 test_erasecolor_premul(r, kARGB_4444_SkColorType, color, 0x88FF0080); 171 test_erasecolor_premul(r, kRGBA_8888_SkColorType, color, color); 172 test_erasecolor_premul(r, kBGRA_8888_SkColorType, color, color); 173 } 174 175 // Test that SkBitmap::ComputeOpaque() is correct for various colortypes. 176 DEF_TEST(Bitmap_compute_is_opaque, r) { 177 SkColorType colorTypes[] = { 178 kAlpha_8_SkColorType, 179 kRGB_565_SkColorType, 180 kARGB_4444_SkColorType, 181 kRGBA_8888_SkColorType, 182 kRGB_888x_SkColorType, 183 kBGRA_8888_SkColorType, 184 kRGBA_1010102_SkColorType, 185 kRGB_101010x_SkColorType, 186 kGray_8_SkColorType, 187 kRGBA_F16_SkColorType, 188 kRGBA_F32_SkColorType, 189 }; 190 for (auto ct : colorTypes) { 191 SkBitmap bm; 192 SkAlphaType at = SkColorTypeIsAlwaysOpaque(ct) ? kOpaque_SkAlphaType : kPremul_SkAlphaType; 193 bm.allocPixels(SkImageInfo::Make(13, 17, ct, at)); 194 bm.eraseColor(SkColorSetARGB(255, 10, 20, 30)); 195 REPORTER_ASSERT(r, SkBitmap::ComputeIsOpaque(bm)); 196 197 bm.eraseColor(SkColorSetARGB(128, 255, 255, 255)); 198 bool isOpaque = SkBitmap::ComputeIsOpaque(bm); 199 bool shouldBeOpaque = (at == kOpaque_SkAlphaType); 200 REPORTER_ASSERT(r, isOpaque == shouldBeOpaque); 201 } 202 } 203 204 // Test that erase+getColor round trips with RGBA_F16 pixels. 205 DEF_TEST(Bitmap_erase_f16_erase_getColor, r) { 206 SkRandom random; 207 SkPixmap pm; 208 SkBitmap bm; 209 bm.allocPixels(SkImageInfo::Make(1, 1, kRGBA_F16_SkColorType, kPremul_SkAlphaType)); 210 REPORTER_ASSERT(r, bm.peekPixels(&pm)); 211 for (unsigned i = 0; i < 0x100; ++i) { 212 // Test all possible values of blue component. 213 SkColor color1 = (SkColor)((random.nextU() & 0xFFFFFF00) | i); 214 // Test all possible values of alpha component. 215 SkColor color2 = (SkColor)((random.nextU() & 0x00FFFFFF) | (i << 24)); 216 for (SkColor color : {color1, color2}) { 217 pm.erase(color); 218 if (SkColorGetA(color) != 0) { 219 REPORTER_ASSERT(r, color == pm.getColor(0, 0)); 220 } else { 221 REPORTER_ASSERT(r, 0 == SkColorGetA(pm.getColor(0, 0))); 222 } 223 } 224 } 225 } 226 227 // Make sure that the bitmap remains valid when pixelref is removed. 228 DEF_TEST(Bitmap_clear_pixelref_keep_info, r) { 229 SkBitmap bm; 230 bm.allocPixels(SkImageInfo::MakeN32Premul(100,100)); 231 bm.setPixelRef(nullptr, 0, 0); 232 SkDEBUGCODE(bm.validate();) 233 } 234 235 // At the time of writing, SkBitmap::erase() works when the color is zero for all formats, 236 // but some formats failed when the color is non-zero! 237 DEF_TEST(Bitmap_erase, r) { 238 SkColorType colorTypes[] = { 239 kRGB_565_SkColorType, 240 kARGB_4444_SkColorType, 241 kRGB_888x_SkColorType, 242 kRGBA_8888_SkColorType, 243 kBGRA_8888_SkColorType, 244 kRGB_101010x_SkColorType, 245 kRGBA_1010102_SkColorType, 246 }; 247 248 for (SkColorType ct : colorTypes) { 249 SkImageInfo info = SkImageInfo::Make(1,1, (SkColorType)ct, kPremul_SkAlphaType); 250 251 SkBitmap bm; 252 bm.allocPixels(info); 253 254 bm.eraseColor(0x00000000); 255 if (SkColorTypeIsAlwaysOpaque(ct)) { 256 REPORTER_ASSERT(r, bm.getColor(0,0) == 0xff000000); 257 } else { 258 REPORTER_ASSERT(r, bm.getColor(0,0) == 0x00000000); 259 } 260 261 bm.eraseColor(0xaabbccdd); 262 REPORTER_ASSERT(r, bm.getColor(0,0) != 0xff000000); 263 REPORTER_ASSERT(r, bm.getColor(0,0) != 0x00000000); 264 } 265 } 266 267 static void check_alphas(skiatest::Reporter* reporter, const SkBitmap& bm, 268 bool (*pred)(float expected, float actual)) { 269 SkASSERT(bm.width() == 16); 270 SkASSERT(bm.height() == 16); 271 272 int alpha = 0; 273 for (int y = 0; y < 16; ++y) { 274 for (int x = 0; x < 16; ++x) { 275 float expected = alpha / 255.0f; 276 float actual = bm.getAlphaf(x, y); 277 if (!pred(expected, actual)) { 278 ERRORF(reporter, "got %g, want %g\n", actual, expected); 279 } 280 alpha += 1; 281 } 282 } 283 } 284 285 static bool unit_compare(float expected, float actual, float tol = 1.0f/(1<<12)) { 286 SkASSERT(expected >= 0 && expected <= 1); 287 SkASSERT( actual >= 0 && actual <= 1); 288 if (expected == 0 || expected == 1) { 289 return actual == expected; 290 } else { 291 return SkScalarNearlyEqual(expected, actual, tol); 292 } 293 } 294 295 static float unit_discretize(float value, float scale) { 296 SkASSERT(value >= 0 && value <= 1); 297 if (value == 1) { 298 return 1; 299 } else { 300 return sk_float_floor(value * scale + 0.5f) / scale; 301 } 302 } 303 304 DEF_TEST(getalphaf, reporter) { 305 SkImageInfo info = SkImageInfo::MakeN32Premul(16, 16); 306 SkBitmap bm; 307 bm.allocPixels(info); 308 309 int alpha = 0; 310 for (int y = 0; y < 16; ++y) { 311 for (int x = 0; x < 16; ++x) { 312 *bm.getAddr32(x, y) = alpha++ << 24; 313 } 314 } 315 316 auto nearly = [](float expected, float actual) -> bool { 317 return unit_compare(expected, actual); 318 }; 319 auto nearly4bit = [](float expected, float actual) -> bool { 320 expected = unit_discretize(expected, 15); 321 return unit_compare(expected, actual); 322 }; 323 auto nearly2bit = [](float expected, float actual) -> bool { 324 expected = unit_discretize(expected, 3); 325 return unit_compare(expected, actual); 326 }; 327 auto opaque = [](float expected, float actual) -> bool { 328 return actual == 1.0f; 329 }; 330 331 auto nearly_half = [](float expected, float actual) -> bool { 332 return unit_compare(expected, actual, 1.0f/(1<<10)); 333 }; 334 335 const struct { 336 SkColorType fColorType; 337 bool (*fPred)(float, float); 338 } recs[] = { 339 { kRGB_565_SkColorType, opaque }, 340 { kGray_8_SkColorType, opaque }, 341 { kRGB_888x_SkColorType, opaque }, 342 { kRGB_101010x_SkColorType, opaque }, 343 344 { kAlpha_8_SkColorType, nearly }, 345 { kRGBA_8888_SkColorType, nearly }, 346 { kBGRA_8888_SkColorType, nearly }, 347 { kRGBA_F16_SkColorType, nearly_half }, 348 { kRGBA_F32_SkColorType, nearly }, 349 350 { kRGBA_1010102_SkColorType, nearly2bit }, 351 352 { kARGB_4444_SkColorType, nearly4bit }, 353 }; 354 355 for (const auto& rec : recs) { 356 SkBitmap tmp; 357 tmp.allocPixels(bm.info().makeColorType(rec.fColorType)); 358 if (bm.readPixels(tmp.pixmap())) { 359 check_alphas(reporter, tmp, rec.fPred); 360 } else { 361 SkDebugf("can't readpixels\n"); 362 } 363 } 364 } 365 366