2 * Copyright 2013 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "include/core/SkBitmap.h"
9 #include "include/core/SkColor.h"
10 #include "include/core/SkColorSpace.h"
11 #include "include/core/SkImageInfo.h"
12 #include "include/core/SkMallocPixelRef.h"
13 #include "include/core/SkPixelRef.h"
14 #include "include/core/SkPixmap.h"
15 #include "include/core/SkRefCnt.h"
16 #include "include/core/SkScalar.h"
17 #include "include/core/SkTypes.h"
18 #include "include/private/SkFloatingPoint.h"
19 #include "include/utils/SkRandom.h"
20 #include "tests/Test.h"
21 #include "tools/ToolUtils.h"
23 #include <initializer_list>
25 static void test_peekpixels(skiatest::Reporter* reporter) {
26 const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
31 // empty should return false
32 REPORTER_ASSERT(reporter, !bm.peekPixels(nullptr));
33 REPORTER_ASSERT(reporter, !bm.peekPixels(&pmap));
35 // no pixels should return false
36 bm.setInfo(SkImageInfo::MakeN32Premul(10, 10));
37 REPORTER_ASSERT(reporter, !bm.peekPixels(nullptr));
38 REPORTER_ASSERT(reporter, !bm.peekPixels(&pmap));
40 // real pixels should return true
42 REPORTER_ASSERT(reporter, bm.peekPixels(nullptr));
43 REPORTER_ASSERT(reporter, bm.peekPixels(&pmap));
44 REPORTER_ASSERT(reporter, pmap.info() == bm.info());
45 REPORTER_ASSERT(reporter, pmap.addr() == bm.getPixels());
46 REPORTER_ASSERT(reporter, pmap.rowBytes() == bm.rowBytes());
49 // https://code.google.com/p/chromium/issues/detail?id=446164
50 static void test_bigalloc(skiatest::Reporter* reporter) {
51 const int width = 0x40000001;
52 const int height = 0x00000096;
53 const SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
56 REPORTER_ASSERT(reporter, !bm.tryAllocPixels(info));
58 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(info, info.minRowBytes());
59 REPORTER_ASSERT(reporter, !pr);
62 static void test_allocpixels(skiatest::Reporter* reporter) {
64 const int height = 10;
65 const SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
66 const size_t explicitRowBytes = info.minRowBytes() + 24;
70 REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes());
72 REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes());
75 REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes());
77 bm.setInfo(info, explicitRowBytes);
78 REPORTER_ASSERT(reporter, explicitRowBytes == bm.rowBytes());
80 REPORTER_ASSERT(reporter, explicitRowBytes == bm.rowBytes());
82 bm.allocPixels(info, explicitRowBytes);
83 REPORTER_ASSERT(reporter, explicitRowBytes == bm.rowBytes());
87 REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes());
89 bm.allocPixels(info, 0);
90 REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes());
93 bool success = bm.setInfo(info, info.minRowBytes() - 1); // invalid for 32bit
94 REPORTER_ASSERT(reporter, !success);
95 REPORTER_ASSERT(reporter, bm.isNull());
97 for (SkColorType ct : {
100 kARGB_4444_SkColorType,
101 kRGBA_8888_SkColorType,
102 kBGRA_8888_SkColorType,
103 kRGB_888x_SkColorType,
104 kRGBA_1010102_SkColorType,
105 kRGB_101010x_SkColorType,
107 kRGBA_F16Norm_SkColorType,
108 kRGBA_F16_SkColorType,
109 kRGBA_F32_SkColorType,
110 kR8G8_unorm_SkColorType,
111 kA16_unorm_SkColorType,
112 kR16G16_unorm_SkColorType,
113 kA16_float_SkColorType,
114 kR16G16_float_SkColorType,
115 kR16G16B16A16_unorm_SkColorType,
117 SkImageInfo imageInfo = info.makeColorType(ct);
118 for (int rowBytesPadding = 1; rowBytesPadding <= 17; rowBytesPadding++) {
120 success = bm.setInfo(imageInfo, imageInfo.minRowBytes() + rowBytesPadding);
121 if (rowBytesPadding % imageInfo.bytesPerPixel() == 0) {
122 REPORTER_ASSERT(reporter, success);
123 success = bm.tryAllocPixels();
124 REPORTER_ASSERT(reporter, success);
126 // Not pixel aligned.
127 REPORTER_ASSERT(reporter, !success);
128 REPORTER_ASSERT(reporter, bm.isNull());
134 static void test_bigwidth(skiatest::Reporter* reporter) {
136 int width = 1 << 29; // *4 will be the high-bit of 32bit int
138 SkImageInfo info = SkImageInfo::MakeA8(width, 1);
139 REPORTER_ASSERT(reporter, bm.setInfo(info));
140 REPORTER_ASSERT(reporter, bm.setInfo(info.makeColorType(kRGB_565_SkColorType)));
142 // for a 4-byte config, this width will compute a rowbytes of 0x80000000,
143 // which does not fit in a int32_t. setConfig should detect this, and fail.
145 // TODO: perhaps skia can relax this, and only require that rowBytes fit
146 // in a uint32_t (or larger), but for now this is the constraint.
148 REPORTER_ASSERT(reporter, !bm.setInfo(info.makeColorType(kN32_SkColorType)));
151 DEF_TEST(Bitmap, reporter) {
152 // Zero-sized bitmaps are allowed
153 for (int width = 0; width < 2; ++width) {
154 for (int height = 0; height < 2; ++height) {
156 bool setConf = bm.setInfo(SkImageInfo::MakeN32Premul(width, height));
157 REPORTER_ASSERT(reporter, setConf);
161 REPORTER_ASSERT(reporter, SkToBool(width & height) != bm.empty());
165 test_bigwidth(reporter);
166 test_allocpixels(reporter);
167 test_bigalloc(reporter);
168 test_peekpixels(reporter);
172 * This test checks that getColor works for both swizzles.
174 DEF_TEST(Bitmap_getColor_Swizzle, r) {
176 source.allocN32Pixels(1,1);
177 source.eraseColor(SK_ColorRED);
178 SkColorType colorTypes[] = {
179 kRGBA_8888_SkColorType,
180 kBGRA_8888_SkColorType,
182 for (SkColorType ct : colorTypes) {
184 if (!ToolUtils::copy_to(©, ct, source)) {
185 ERRORF(r, "SkBitmap::copy failed %d", (int)ct);
188 REPORTER_ASSERT(r, source.getColor(0, 0) == copy.getColor(0, 0));
192 static void test_erasecolor_premul(skiatest::Reporter* reporter, SkColorType ct, SkColor input,
195 bm.allocPixels(SkImageInfo::Make(1, 1, ct, kPremul_SkAlphaType));
196 bm.eraseColor(input);
197 INFOF(reporter, "expected: %x actual: %x\n", expected, bm.getColor(0, 0));
198 REPORTER_ASSERT(reporter, bm.getColor(0, 0) == expected);
202 * This test checks that eraseColor premultiplies the color correctly.
204 DEF_TEST(Bitmap_eraseColor_Premul, r) {
205 SkColor color = 0x80FF0080;
206 test_erasecolor_premul(r, kAlpha_8_SkColorType, color, 0x80000000);
207 test_erasecolor_premul(r, kRGB_565_SkColorType, color, 0xFF840042);
208 test_erasecolor_premul(r, kARGB_4444_SkColorType, color, 0x88FF0080);
209 test_erasecolor_premul(r, kRGBA_8888_SkColorType, color, color);
210 test_erasecolor_premul(r, kBGRA_8888_SkColorType, color, color);
213 // Test that SkBitmap::ComputeOpaque() is correct for various colortypes.
214 DEF_TEST(Bitmap_compute_is_opaque, r) {
216 for (int i = 1; i <= kLastEnum_SkColorType; ++i) {
217 SkColorType ct = (SkColorType) i;
219 SkAlphaType at = SkColorTypeIsAlwaysOpaque(ct) ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
220 bm.allocPixels(SkImageInfo::Make(13, 17, ct, at));
221 bm.eraseColor(SkColorSetARGB(255, 10, 20, 30));
222 REPORTER_ASSERT(r, SkBitmap::ComputeIsOpaque(bm));
224 bm.eraseColor(SkColorSetARGB(128, 255, 255, 255));
225 bool isOpaque = SkBitmap::ComputeIsOpaque(bm);
226 bool shouldBeOpaque = (at == kOpaque_SkAlphaType);
227 REPORTER_ASSERT(r, isOpaque == shouldBeOpaque);
231 // Test that erase+getColor round trips with RGBA_F16 pixels.
232 DEF_TEST(Bitmap_erase_f16_erase_getColor, r) {
236 bm.allocPixels(SkImageInfo::Make(1, 1, kRGBA_F16_SkColorType, kPremul_SkAlphaType));
237 REPORTER_ASSERT(r, bm.peekPixels(&pm));
238 for (unsigned i = 0; i < 0x100; ++i) {
239 // Test all possible values of blue component.
240 SkColor color1 = (SkColor)((random.nextU() & 0xFFFFFF00) | i);
241 // Test all possible values of alpha component.
242 SkColor color2 = (SkColor)((random.nextU() & 0x00FFFFFF) | (i << 24));
243 for (SkColor color : {color1, color2}) {
245 if (SkColorGetA(color) != 0) {
246 REPORTER_ASSERT(r, color == pm.getColor(0, 0));
248 REPORTER_ASSERT(r, 0 == SkColorGetA(pm.getColor(0, 0)));
254 // Verify that SkBitmap::erase erases in SRGB, regardless of the SkColorSpace of the
256 DEF_TEST(Bitmap_erase_srgb, r) {
258 // Use a color spin from SRGB.
259 bm.allocPixels(SkImageInfo::Make(1, 1, kN32_SkColorType, kPremul_SkAlphaType,
260 SkColorSpace::MakeSRGB()->makeColorSpin()));
261 // RED will be converted into the spun color space.
262 bm.eraseColor(SK_ColorRED);
263 // getColor doesn't take the color space into account, so the returned color
264 // is different due to the color spin.
265 REPORTER_ASSERT(r, bm.getColor(0, 0) == SK_ColorBLUE);
268 // Make sure that the bitmap remains valid when pixelref is removed.
269 DEF_TEST(Bitmap_clear_pixelref_keep_info, r) {
271 bm.allocPixels(SkImageInfo::MakeN32Premul(100,100));
272 bm.setPixelRef(nullptr, 0, 0);
273 SkDEBUGCODE(bm.validate();)
276 // At the time of writing, SkBitmap::erase() works when the color is zero for all formats,
277 // but some formats failed when the color is non-zero!
278 DEF_TEST(Bitmap_erase, r) {
279 SkColorType colorTypes[] = {
280 kRGB_565_SkColorType,
281 kARGB_4444_SkColorType,
282 kRGB_888x_SkColorType,
283 kRGBA_8888_SkColorType,
284 kBGRA_8888_SkColorType,
285 kRGB_101010x_SkColorType,
286 kRGBA_1010102_SkColorType,
289 for (SkColorType ct : colorTypes) {
290 SkImageInfo info = SkImageInfo::Make(1,1, (SkColorType)ct, kPremul_SkAlphaType);
293 bm.allocPixels(info);
295 bm.eraseColor(0x00000000);
296 if (SkColorTypeIsAlwaysOpaque(ct)) {
297 REPORTER_ASSERT(r, bm.getColor(0,0) == 0xff000000);
299 REPORTER_ASSERT(r, bm.getColor(0,0) == 0x00000000);
302 bm.eraseColor(0xaabbccdd);
303 REPORTER_ASSERT(r, bm.getColor(0,0) != 0xff000000);
304 REPORTER_ASSERT(r, bm.getColor(0,0) != 0x00000000);
308 static void check_alphas(skiatest::Reporter* reporter, const SkBitmap& bm,
309 bool (*pred)(float expected, float actual), SkColorType ct) {
310 SkASSERT(bm.width() == 16);
311 SkASSERT(bm.height() == 16);
314 for (int y = 0; y < 16; ++y) {
315 for (int x = 0; x < 16; ++x) {
316 float expected = alpha / 255.0f;
317 float actual = bm.getAlphaf(x, y);
318 if (!pred(expected, actual)) {
319 ERRORF(reporter, "%s: got %g, want %g\n",
320 ToolUtils::colortype_name(ct), actual, expected);
327 static bool unit_compare(float expected, float actual, float tol = 1.0f/(1<<12)) {
328 SkASSERT(expected >= 0 && expected <= 1);
329 SkASSERT( actual >= 0 && actual <= 1);
330 if (expected == 0 || expected == 1) {
331 return actual == expected;
333 return SkScalarNearlyEqual(expected, actual, tol);
337 static float unit_discretize(float value, float scale) {
338 SkASSERT(value >= 0 && value <= 1);
342 return sk_float_floor(value * scale + 0.5f) / scale;
346 DEF_TEST(getalphaf, reporter) {
347 SkImageInfo info = SkImageInfo::MakeN32Premul(16, 16);
349 bm.allocPixels(info);
352 for (int y = 0; y < 16; ++y) {
353 for (int x = 0; x < 16; ++x) {
354 *bm.getAddr32(x, y) = alpha++ << 24;
358 auto nearly = [](float expected, float actual) -> bool {
359 return unit_compare(expected, actual);
361 auto nearly4bit = [](float expected, float actual) -> bool {
362 expected = unit_discretize(expected, 15);
363 return unit_compare(expected, actual);
365 auto nearly2bit = [](float expected, float actual) -> bool {
366 expected = unit_discretize(expected, 3);
367 return unit_compare(expected, actual);
369 auto opaque = [](float expected, float actual) -> bool {
370 return actual == 1.0f;
373 auto nearly_half = [](float expected, float actual) -> bool {
374 return unit_compare(expected, actual, 1.0f/(1<<10));
378 SkColorType fColorType;
379 bool (*fPred)(float, float);
381 { kRGB_565_SkColorType, opaque },
382 { kGray_8_SkColorType, opaque },
383 { kR8G8_unorm_SkColorType, opaque },
384 { kR16G16_unorm_SkColorType, opaque },
385 { kR16G16_float_SkColorType, opaque },
386 { kRGB_888x_SkColorType, opaque },
387 { kRGB_101010x_SkColorType, opaque },
389 { kAlpha_8_SkColorType, nearly },
390 { kA16_unorm_SkColorType, nearly },
391 { kA16_float_SkColorType, nearly_half },
392 { kRGBA_8888_SkColorType, nearly },
393 { kBGRA_8888_SkColorType, nearly },
394 { kR16G16B16A16_unorm_SkColorType, nearly },
395 { kRGBA_F16_SkColorType, nearly_half },
396 { kRGBA_F32_SkColorType, nearly },
398 { kRGBA_1010102_SkColorType, nearly2bit },
400 { kARGB_4444_SkColorType, nearly4bit },
403 for (const auto& rec : recs) {
405 tmp.allocPixels(bm.info().makeColorType(rec.fColorType));
406 if (bm.readPixels(tmp.pixmap())) {
407 check_alphas(reporter, tmp, rec.fPred, rec.fColorType);
409 SkDebugf("can't readpixels\n");
414 /* computeByteSize() is documented to return 0 if height is zero, but does not
415 * special-case width==0, so computeByteSize() can return non-zero for that
416 * (since it is defined to return (height-1)*rb + ...
418 * Test that allocPixels() respects this, and allocates a buffer as large as
419 * computeByteSize()... even though the bitmap is logicallly empty.
421 DEF_TEST(bitmap_zerowidth_crbug_1103827, reporter) {
422 const size_t big_rb = 1 << 16;
426 size_t rowbytes, expected_size;
428 { 2, 0, big_rb, 0 }, // zero-height means zero-size
429 { 0, 2, big_rb, big_rb }, // zero-width is computed normally
432 for (const auto& r : rec) {
433 auto info = SkImageInfo::Make(r.width, r.height,
434 kRGBA_8888_SkColorType, kPremul_SkAlphaType);
435 size_t size = info.computeByteSize(r.rowbytes);
436 REPORTER_ASSERT(reporter, size == r.expected_size);
439 bm.setInfo(info, r.rowbytes);
440 REPORTER_ASSERT(reporter, size == bm.computeByteSize());
442 // Be sure we can actually write to that much memory. If the bitmap underallocated
443 // the buffer, this should trash memory and crash (we hope).
445 sk_bzero(bm.getPixels(), size);