123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369 |
- /*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "include/core/SkBitmap.h"
- #include "include/core/SkColor.h"
- #include "include/core/SkImageInfo.h"
- #include "include/core/SkMallocPixelRef.h"
- #include "include/core/SkPixelRef.h"
- #include "include/core/SkPixmap.h"
- #include "include/core/SkRefCnt.h"
- #include "include/core/SkScalar.h"
- #include "include/core/SkTypes.h"
- #include "include/private/SkFloatingPoint.h"
- #include "include/utils/SkRandom.h"
- #include "tests/Test.h"
- #include "tools/ToolUtils.h"
- #include <initializer_list>
- static void test_peekpixels(skiatest::Reporter* reporter) {
- const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
- SkPixmap pmap;
- SkBitmap bm;
- // empty should return false
- REPORTER_ASSERT(reporter, !bm.peekPixels(nullptr));
- REPORTER_ASSERT(reporter, !bm.peekPixels(&pmap));
- // no pixels should return false
- bm.setInfo(SkImageInfo::MakeN32Premul(10, 10));
- REPORTER_ASSERT(reporter, !bm.peekPixels(nullptr));
- REPORTER_ASSERT(reporter, !bm.peekPixels(&pmap));
- // real pixels should return true
- bm.allocPixels(info);
- REPORTER_ASSERT(reporter, bm.peekPixels(nullptr));
- REPORTER_ASSERT(reporter, bm.peekPixels(&pmap));
- REPORTER_ASSERT(reporter, pmap.info() == bm.info());
- REPORTER_ASSERT(reporter, pmap.addr() == bm.getPixels());
- REPORTER_ASSERT(reporter, pmap.rowBytes() == bm.rowBytes());
- }
- // https://code.google.com/p/chromium/issues/detail?id=446164
- static void test_bigalloc(skiatest::Reporter* reporter) {
- const int width = 0x40000001;
- const int height = 0x00000096;
- const SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
- SkBitmap bm;
- REPORTER_ASSERT(reporter, !bm.tryAllocPixels(info));
- sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(info, info.minRowBytes());
- REPORTER_ASSERT(reporter, !pr);
- }
- static void test_allocpixels(skiatest::Reporter* reporter) {
- const int width = 10;
- const int height = 10;
- const SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
- const size_t explicitRowBytes = info.minRowBytes() + 24;
- SkBitmap bm;
- bm.setInfo(info);
- REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes());
- bm.allocPixels();
- REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes());
- bm.reset();
- bm.allocPixels(info);
- REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes());
- bm.setInfo(info, explicitRowBytes);
- REPORTER_ASSERT(reporter, explicitRowBytes == bm.rowBytes());
- bm.allocPixels();
- REPORTER_ASSERT(reporter, explicitRowBytes == bm.rowBytes());
- bm.reset();
- bm.allocPixels(info, explicitRowBytes);
- REPORTER_ASSERT(reporter, explicitRowBytes == bm.rowBytes());
- bm.reset();
- bm.setInfo(info, 0);
- REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes());
- bm.reset();
- bm.allocPixels(info, 0);
- REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes());
- bm.reset();
- bool success = bm.setInfo(info, info.minRowBytes() - 1); // invalid for 32bit
- REPORTER_ASSERT(reporter, !success);
- REPORTER_ASSERT(reporter, bm.isNull());
- }
- static void test_bigwidth(skiatest::Reporter* reporter) {
- SkBitmap bm;
- int width = 1 << 29; // *4 will be the high-bit of 32bit int
- SkImageInfo info = SkImageInfo::MakeA8(width, 1);
- REPORTER_ASSERT(reporter, bm.setInfo(info));
- REPORTER_ASSERT(reporter, bm.setInfo(info.makeColorType(kRGB_565_SkColorType)));
- // for a 4-byte config, this width will compute a rowbytes of 0x80000000,
- // which does not fit in a int32_t. setConfig should detect this, and fail.
- // TODO: perhaps skia can relax this, and only require that rowBytes fit
- // in a uint32_t (or larger), but for now this is the constraint.
- REPORTER_ASSERT(reporter, !bm.setInfo(info.makeColorType(kN32_SkColorType)));
- }
- /**
- * This test contains basic sanity checks concerning bitmaps.
- */
- DEF_TEST(Bitmap, reporter) {
- // Zero-sized bitmaps are allowed
- for (int width = 0; width < 2; ++width) {
- for (int height = 0; height < 2; ++height) {
- SkBitmap bm;
- bool setConf = bm.setInfo(SkImageInfo::MakeN32Premul(width, height));
- REPORTER_ASSERT(reporter, setConf);
- if (setConf) {
- bm.allocPixels();
- }
- REPORTER_ASSERT(reporter, SkToBool(width & height) != bm.empty());
- }
- }
- test_bigwidth(reporter);
- test_allocpixels(reporter);
- test_bigalloc(reporter);
- test_peekpixels(reporter);
- }
- /**
- * This test checks that getColor works for both swizzles.
- */
- DEF_TEST(Bitmap_getColor_Swizzle, r) {
- SkBitmap source;
- source.allocN32Pixels(1,1);
- source.eraseColor(SK_ColorRED);
- SkColorType colorTypes[] = {
- kRGBA_8888_SkColorType,
- kBGRA_8888_SkColorType,
- };
- for (SkColorType ct : colorTypes) {
- SkBitmap copy;
- if (!ToolUtils::copy_to(©, ct, source)) {
- ERRORF(r, "SkBitmap::copy failed %d", (int)ct);
- continue;
- }
- REPORTER_ASSERT(r, source.getColor(0, 0) == copy.getColor(0, 0));
- }
- }
- static void test_erasecolor_premul(skiatest::Reporter* reporter, SkColorType ct, SkColor input,
- SkColor expected) {
- SkBitmap bm;
- bm.allocPixels(SkImageInfo::Make(1, 1, ct, kPremul_SkAlphaType));
- bm.eraseColor(input);
- INFOF(reporter, "expected: %x actual: %x\n", expected, bm.getColor(0, 0));
- REPORTER_ASSERT(reporter, bm.getColor(0, 0) == expected);
- }
- /**
- * This test checks that eraseColor premultiplies the color correctly.
- */
- DEF_TEST(Bitmap_eraseColor_Premul, r) {
- SkColor color = 0x80FF0080;
- test_erasecolor_premul(r, kAlpha_8_SkColorType, color, 0x80000000);
- test_erasecolor_premul(r, kRGB_565_SkColorType, color, 0xFF840042);
- test_erasecolor_premul(r, kARGB_4444_SkColorType, color, 0x88FF0080);
- test_erasecolor_premul(r, kRGBA_8888_SkColorType, color, color);
- test_erasecolor_premul(r, kBGRA_8888_SkColorType, color, color);
- }
- // Test that SkBitmap::ComputeOpaque() is correct for various colortypes.
- DEF_TEST(Bitmap_compute_is_opaque, r) {
- SkColorType colorTypes[] = {
- kAlpha_8_SkColorType,
- kRGB_565_SkColorType,
- kARGB_4444_SkColorType,
- kRGBA_8888_SkColorType,
- kRGB_888x_SkColorType,
- kBGRA_8888_SkColorType,
- kRGBA_1010102_SkColorType,
- kRGB_101010x_SkColorType,
- kGray_8_SkColorType,
- kRGBA_F16_SkColorType,
- kRGBA_F32_SkColorType,
- };
- for (auto ct : colorTypes) {
- SkBitmap bm;
- SkAlphaType at = SkColorTypeIsAlwaysOpaque(ct) ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
- bm.allocPixels(SkImageInfo::Make(13, 17, ct, at));
- bm.eraseColor(SkColorSetARGB(255, 10, 20, 30));
- REPORTER_ASSERT(r, SkBitmap::ComputeIsOpaque(bm));
- bm.eraseColor(SkColorSetARGB(128, 255, 255, 255));
- bool isOpaque = SkBitmap::ComputeIsOpaque(bm);
- bool shouldBeOpaque = (at == kOpaque_SkAlphaType);
- REPORTER_ASSERT(r, isOpaque == shouldBeOpaque);
- }
- }
- // Test that erase+getColor round trips with RGBA_F16 pixels.
- DEF_TEST(Bitmap_erase_f16_erase_getColor, r) {
- SkRandom random;
- SkPixmap pm;
- SkBitmap bm;
- bm.allocPixels(SkImageInfo::Make(1, 1, kRGBA_F16_SkColorType, kPremul_SkAlphaType));
- REPORTER_ASSERT(r, bm.peekPixels(&pm));
- for (unsigned i = 0; i < 0x100; ++i) {
- // Test all possible values of blue component.
- SkColor color1 = (SkColor)((random.nextU() & 0xFFFFFF00) | i);
- // Test all possible values of alpha component.
- SkColor color2 = (SkColor)((random.nextU() & 0x00FFFFFF) | (i << 24));
- for (SkColor color : {color1, color2}) {
- pm.erase(color);
- if (SkColorGetA(color) != 0) {
- REPORTER_ASSERT(r, color == pm.getColor(0, 0));
- } else {
- REPORTER_ASSERT(r, 0 == SkColorGetA(pm.getColor(0, 0)));
- }
- }
- }
- }
- // Make sure that the bitmap remains valid when pixelref is removed.
- DEF_TEST(Bitmap_clear_pixelref_keep_info, r) {
- SkBitmap bm;
- bm.allocPixels(SkImageInfo::MakeN32Premul(100,100));
- bm.setPixelRef(nullptr, 0, 0);
- SkDEBUGCODE(bm.validate();)
- }
- // At the time of writing, SkBitmap::erase() works when the color is zero for all formats,
- // but some formats failed when the color is non-zero!
- DEF_TEST(Bitmap_erase, r) {
- SkColorType colorTypes[] = {
- kRGB_565_SkColorType,
- kARGB_4444_SkColorType,
- kRGB_888x_SkColorType,
- kRGBA_8888_SkColorType,
- kBGRA_8888_SkColorType,
- kRGB_101010x_SkColorType,
- kRGBA_1010102_SkColorType,
- };
- for (SkColorType ct : colorTypes) {
- SkImageInfo info = SkImageInfo::Make(1,1, (SkColorType)ct, kPremul_SkAlphaType);
- SkBitmap bm;
- bm.allocPixels(info);
- bm.eraseColor(0x00000000);
- if (SkColorTypeIsAlwaysOpaque(ct)) {
- REPORTER_ASSERT(r, bm.getColor(0,0) == 0xff000000);
- } else {
- REPORTER_ASSERT(r, bm.getColor(0,0) == 0x00000000);
- }
- bm.eraseColor(0xaabbccdd);
- REPORTER_ASSERT(r, bm.getColor(0,0) != 0xff000000);
- REPORTER_ASSERT(r, bm.getColor(0,0) != 0x00000000);
- }
- }
- static void check_alphas(skiatest::Reporter* reporter, const SkBitmap& bm,
- bool (*pred)(float expected, float actual)) {
- SkASSERT(bm.width() == 16);
- SkASSERT(bm.height() == 16);
- int alpha = 0;
- for (int y = 0; y < 16; ++y) {
- for (int x = 0; x < 16; ++x) {
- float expected = alpha / 255.0f;
- float actual = bm.getAlphaf(x, y);
- if (!pred(expected, actual)) {
- ERRORF(reporter, "got %g, want %g\n", actual, expected);
- }
- alpha += 1;
- }
- }
- }
- static bool unit_compare(float expected, float actual, float tol = 1.0f/(1<<12)) {
- SkASSERT(expected >= 0 && expected <= 1);
- SkASSERT( actual >= 0 && actual <= 1);
- if (expected == 0 || expected == 1) {
- return actual == expected;
- } else {
- return SkScalarNearlyEqual(expected, actual, tol);
- }
- }
- static float unit_discretize(float value, float scale) {
- SkASSERT(value >= 0 && value <= 1);
- if (value == 1) {
- return 1;
- } else {
- return sk_float_floor(value * scale + 0.5f) / scale;
- }
- }
- DEF_TEST(getalphaf, reporter) {
- SkImageInfo info = SkImageInfo::MakeN32Premul(16, 16);
- SkBitmap bm;
- bm.allocPixels(info);
- int alpha = 0;
- for (int y = 0; y < 16; ++y) {
- for (int x = 0; x < 16; ++x) {
- *bm.getAddr32(x, y) = alpha++ << 24;
- }
- }
- auto nearly = [](float expected, float actual) -> bool {
- return unit_compare(expected, actual);
- };
- auto nearly4bit = [](float expected, float actual) -> bool {
- expected = unit_discretize(expected, 15);
- return unit_compare(expected, actual);
- };
- auto nearly2bit = [](float expected, float actual) -> bool {
- expected = unit_discretize(expected, 3);
- return unit_compare(expected, actual);
- };
- auto opaque = [](float expected, float actual) -> bool {
- return actual == 1.0f;
- };
- auto nearly_half = [](float expected, float actual) -> bool {
- return unit_compare(expected, actual, 1.0f/(1<<10));
- };
- const struct {
- SkColorType fColorType;
- bool (*fPred)(float, float);
- } recs[] = {
- { kRGB_565_SkColorType, opaque },
- { kGray_8_SkColorType, opaque },
- { kRGB_888x_SkColorType, opaque },
- { kRGB_101010x_SkColorType, opaque },
- { kAlpha_8_SkColorType, nearly },
- { kRGBA_8888_SkColorType, nearly },
- { kBGRA_8888_SkColorType, nearly },
- { kRGBA_F16_SkColorType, nearly_half },
- { kRGBA_F32_SkColorType, nearly },
- { kRGBA_1010102_SkColorType, nearly2bit },
- { kARGB_4444_SkColorType, nearly4bit },
- };
- for (const auto& rec : recs) {
- SkBitmap tmp;
- tmp.allocPixels(bm.info().makeColorType(rec.fColorType));
- if (bm.readPixels(tmp.pixmap())) {
- check_alphas(reporter, tmp, rec.fPred);
- } else {
- SkDebugf("can't readpixels\n");
- }
- }
- }
|