1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2011 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h" 9cb93a386Sopenharmony_ci#include "include/core/SkColor.h" 10cb93a386Sopenharmony_ci#include "include/core/SkColorSpace.h" 11cb93a386Sopenharmony_ci#include "include/core/SkImageInfo.h" 12cb93a386Sopenharmony_ci#include "include/core/SkPoint.h" 13cb93a386Sopenharmony_ci#include "include/core/SkRect.h" 14cb93a386Sopenharmony_ci#include "include/core/SkRefCnt.h" 15cb93a386Sopenharmony_ci#include "include/core/SkSize.h" 16cb93a386Sopenharmony_ci#include "include/core/SkTypes.h" 17cb93a386Sopenharmony_ci#include "src/core/SkOpts.h" 18cb93a386Sopenharmony_ci#include "tests/Test.h" 19cb93a386Sopenharmony_ci#include "tools/ToolUtils.h" 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_cistatic void init_src(const SkBitmap& bitmap) { 22cb93a386Sopenharmony_ci if (bitmap.getPixels()) { 23cb93a386Sopenharmony_ci bitmap.eraseColor(SK_ColorWHITE); 24cb93a386Sopenharmony_ci } 25cb93a386Sopenharmony_ci} 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_cistruct Pair { 28cb93a386Sopenharmony_ci SkColorType fColorType; 29cb93a386Sopenharmony_ci const char* fValid; 30cb93a386Sopenharmony_ci}; 31cb93a386Sopenharmony_ci 32cb93a386Sopenharmony_ci// Utility functions for copyPixelsTo()/copyPixelsFrom() tests. 33cb93a386Sopenharmony_ci// getPixel() 34cb93a386Sopenharmony_ci// setPixel() 35cb93a386Sopenharmony_ci// getSkConfigName() 36cb93a386Sopenharmony_ci// struct Coordinates 37cb93a386Sopenharmony_ci// reportCopyVerification() 38cb93a386Sopenharmony_ci// writeCoordPixels() 39cb93a386Sopenharmony_ci 40cb93a386Sopenharmony_ci// Helper struct to contain pixel locations, while avoiding need for STL. 41cb93a386Sopenharmony_cistruct Coordinates { 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ci const int length; 44cb93a386Sopenharmony_ci SkIPoint* const data; 45cb93a386Sopenharmony_ci 46cb93a386Sopenharmony_ci explicit Coordinates(int _length): length(_length) 47cb93a386Sopenharmony_ci , data(new SkIPoint[length]) { } 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_ci ~Coordinates(){ 50cb93a386Sopenharmony_ci delete [] data; 51cb93a386Sopenharmony_ci } 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_ci SkIPoint* operator[](int i) const { 54cb93a386Sopenharmony_ci // Use with care, no bounds checking. 55cb93a386Sopenharmony_ci return data + i; 56cb93a386Sopenharmony_ci } 57cb93a386Sopenharmony_ci}; 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_cistatic const Pair gPairs[] = { 60cb93a386Sopenharmony_ci { kUnknown_SkColorType, "0000000" }, 61cb93a386Sopenharmony_ci { kAlpha_8_SkColorType, "0100000" }, 62cb93a386Sopenharmony_ci { kRGB_565_SkColorType, "0101011" }, 63cb93a386Sopenharmony_ci { kARGB_4444_SkColorType, "0101111" }, 64cb93a386Sopenharmony_ci { kN32_SkColorType, "0101111" }, 65cb93a386Sopenharmony_ci { kRGBA_F16_SkColorType, "0101011" }, 66cb93a386Sopenharmony_ci}; 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_cistatic void setup_src_bitmaps(SkBitmap* srcOpaque, SkBitmap* srcPremul, 69cb93a386Sopenharmony_ci SkColorType ct) { 70cb93a386Sopenharmony_ci const int W = 20; 71cb93a386Sopenharmony_ci const int H = 33; 72cb93a386Sopenharmony_ci sk_sp<SkColorSpace> colorSpace = nullptr; 73cb93a386Sopenharmony_ci if (kRGBA_F16_SkColorType == ct) { 74cb93a386Sopenharmony_ci colorSpace = SkColorSpace::MakeSRGB(); 75cb93a386Sopenharmony_ci } 76cb93a386Sopenharmony_ci 77cb93a386Sopenharmony_ci srcOpaque->allocPixels(SkImageInfo::Make(W, H, ct, kOpaque_SkAlphaType, colorSpace)); 78cb93a386Sopenharmony_ci srcPremul->allocPixels(SkImageInfo::Make(W, H, ct, kPremul_SkAlphaType, colorSpace)); 79cb93a386Sopenharmony_ci init_src(*srcOpaque); 80cb93a386Sopenharmony_ci init_src(*srcPremul); 81cb93a386Sopenharmony_ci} 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_ciDEF_TEST(BitmapCopy_extractSubset, reporter) { 84cb93a386Sopenharmony_ci const int W = 20; 85cb93a386Sopenharmony_ci for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) { 86cb93a386Sopenharmony_ci SkBitmap srcOpaque, srcPremul; 87cb93a386Sopenharmony_ci setup_src_bitmaps(&srcOpaque, &srcPremul, gPairs[i].fColorType); 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_ci SkBitmap bitmap(srcOpaque); 90cb93a386Sopenharmony_ci SkBitmap subset; 91cb93a386Sopenharmony_ci SkIRect r; 92cb93a386Sopenharmony_ci // Extract a subset which has the same width as the original. This 93cb93a386Sopenharmony_ci // catches a bug where we cloned the genID incorrectly. 94cb93a386Sopenharmony_ci r.setLTRB(0, 1, W, 3); 95cb93a386Sopenharmony_ci // Relies on old behavior of extractSubset failing if colortype is unknown 96cb93a386Sopenharmony_ci if (kUnknown_SkColorType != bitmap.colorType() && bitmap.extractSubset(&subset, r)) { 97cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, subset.width() == W); 98cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, subset.height() == 2); 99cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, subset.alphaType() == bitmap.alphaType()); 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ci // Test copying an extracted subset. 102cb93a386Sopenharmony_ci for (size_t j = 0; j < SK_ARRAY_COUNT(gPairs); j++) { 103cb93a386Sopenharmony_ci SkBitmap copy; 104cb93a386Sopenharmony_ci bool success = ToolUtils::copy_to(©, gPairs[j].fColorType, subset); 105cb93a386Sopenharmony_ci if (!success) { 106cb93a386Sopenharmony_ci // Skip checking that success matches fValid, which is redundant 107cb93a386Sopenharmony_ci // with the code below. 108cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, gPairs[i].fColorType != gPairs[j].fColorType); 109cb93a386Sopenharmony_ci continue; 110cb93a386Sopenharmony_ci } 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci // When performing a copy of an extracted subset, the gen id should 113cb93a386Sopenharmony_ci // change. 114cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, copy.getGenerationID() != subset.getGenerationID()); 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, copy.width() == W); 117cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, copy.height() == 2); 118cb93a386Sopenharmony_ci } 119cb93a386Sopenharmony_ci } 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ci bitmap = srcPremul; 122cb93a386Sopenharmony_ci if (bitmap.extractSubset(&subset, r)) { 123cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, subset.alphaType() == bitmap.alphaType()); 124cb93a386Sopenharmony_ci } 125cb93a386Sopenharmony_ci } 126cb93a386Sopenharmony_ci} 127cb93a386Sopenharmony_ci 128cb93a386Sopenharmony_ci#include "include/core/SkColorPriv.h" 129cb93a386Sopenharmony_ci#include "src/core/SkUtils.h" 130cb93a386Sopenharmony_ci 131cb93a386Sopenharmony_ci/** 132cb93a386Sopenharmony_ci * Construct 4x4 pixels where we can look at a color and determine where it should be in the grid. 133cb93a386Sopenharmony_ci * alpha = 0xFF, blue = 0x80, red = x, green = y 134cb93a386Sopenharmony_ci */ 135cb93a386Sopenharmony_cistatic void fill_4x4_pixels(SkPMColor colors[16]) { 136cb93a386Sopenharmony_ci for (int y = 0; y < 4; ++y) { 137cb93a386Sopenharmony_ci for (int x = 0; x < 4; ++x) { 138cb93a386Sopenharmony_ci colors[y*4+x] = SkPackARGB32(0xFF, x, y, 0x80); 139cb93a386Sopenharmony_ci } 140cb93a386Sopenharmony_ci } 141cb93a386Sopenharmony_ci} 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_cistatic bool check_4x4_pixel(SkPMColor color, unsigned x, unsigned y) { 144cb93a386Sopenharmony_ci SkASSERT(x < 4 && y < 4); 145cb93a386Sopenharmony_ci return 0xFF == SkGetPackedA32(color) && 146cb93a386Sopenharmony_ci x == SkGetPackedR32(color) && 147cb93a386Sopenharmony_ci y == SkGetPackedG32(color) && 148cb93a386Sopenharmony_ci 0x80 == SkGetPackedB32(color); 149cb93a386Sopenharmony_ci} 150cb93a386Sopenharmony_ci 151cb93a386Sopenharmony_ci/** 152cb93a386Sopenharmony_ci * Fill with all zeros, which will never match any value from fill_4x4_pixels 153cb93a386Sopenharmony_ci */ 154cb93a386Sopenharmony_cistatic void clear_4x4_pixels(SkPMColor colors[16]) { 155cb93a386Sopenharmony_ci sk_memset32(colors, 0, 16); 156cb93a386Sopenharmony_ci} 157cb93a386Sopenharmony_ci 158cb93a386Sopenharmony_ci// Much of readPixels is exercised by copyTo testing, since readPixels is the backend for that 159cb93a386Sopenharmony_ci// method. Here we explicitly test subset copies. 160cb93a386Sopenharmony_ci// 161cb93a386Sopenharmony_ciDEF_TEST(BitmapReadPixels, reporter) { 162cb93a386Sopenharmony_ci const int W = 4; 163cb93a386Sopenharmony_ci const int H = 4; 164cb93a386Sopenharmony_ci const size_t rowBytes = W * sizeof(SkPMColor); 165cb93a386Sopenharmony_ci const SkImageInfo srcInfo = SkImageInfo::MakeN32Premul(W, H); 166cb93a386Sopenharmony_ci SkPMColor srcPixels[16]; 167cb93a386Sopenharmony_ci fill_4x4_pixels(srcPixels); 168cb93a386Sopenharmony_ci SkBitmap srcBM; 169cb93a386Sopenharmony_ci srcBM.installPixels(srcInfo, srcPixels, rowBytes); 170cb93a386Sopenharmony_ci 171cb93a386Sopenharmony_ci SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(W, H); 172cb93a386Sopenharmony_ci SkPMColor dstPixels[16]; 173cb93a386Sopenharmony_ci 174cb93a386Sopenharmony_ci const struct { 175cb93a386Sopenharmony_ci bool fExpectedSuccess; 176cb93a386Sopenharmony_ci SkIPoint fRequestedSrcLoc; 177cb93a386Sopenharmony_ci SkISize fRequestedDstSize; 178cb93a386Sopenharmony_ci // If fExpectedSuccess, check these, otherwise ignore 179cb93a386Sopenharmony_ci SkIPoint fExpectedDstLoc; 180cb93a386Sopenharmony_ci SkIRect fExpectedSrcR; 181cb93a386Sopenharmony_ci } gRec[] = { 182cb93a386Sopenharmony_ci { true, { 0, 0 }, { 4, 4 }, { 0, 0 }, { 0, 0, 4, 4 } }, 183cb93a386Sopenharmony_ci { true, { 1, 1 }, { 2, 2 }, { 0, 0 }, { 1, 1, 3, 3 } }, 184cb93a386Sopenharmony_ci { true, { 2, 2 }, { 4, 4 }, { 0, 0 }, { 2, 2, 4, 4 } }, 185cb93a386Sopenharmony_ci { true, {-1,-1 }, { 2, 2 }, { 1, 1 }, { 0, 0, 1, 1 } }, 186cb93a386Sopenharmony_ci { false, {-1,-1 }, { 1, 1 }, { 0, 0 }, { 0, 0, 0, 0 } }, 187cb93a386Sopenharmony_ci }; 188cb93a386Sopenharmony_ci 189cb93a386Sopenharmony_ci for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { 190cb93a386Sopenharmony_ci clear_4x4_pixels(dstPixels); 191cb93a386Sopenharmony_ci 192cb93a386Sopenharmony_ci dstInfo = dstInfo.makeDimensions(gRec[i].fRequestedDstSize); 193cb93a386Sopenharmony_ci bool success = srcBM.readPixels(dstInfo, dstPixels, rowBytes, 194cb93a386Sopenharmony_ci gRec[i].fRequestedSrcLoc.x(), gRec[i].fRequestedSrcLoc.y()); 195cb93a386Sopenharmony_ci 196cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, gRec[i].fExpectedSuccess == success); 197cb93a386Sopenharmony_ci if (success) { 198cb93a386Sopenharmony_ci const SkIRect srcR = gRec[i].fExpectedSrcR; 199cb93a386Sopenharmony_ci const int dstX = gRec[i].fExpectedDstLoc.x(); 200cb93a386Sopenharmony_ci const int dstY = gRec[i].fExpectedDstLoc.y(); 201cb93a386Sopenharmony_ci // Walk the dst pixels, and check if we got what we expected 202cb93a386Sopenharmony_ci for (int y = 0; y < H; ++y) { 203cb93a386Sopenharmony_ci for (int x = 0; x < W; ++x) { 204cb93a386Sopenharmony_ci SkPMColor dstC = dstPixels[y*4+x]; 205cb93a386Sopenharmony_ci // get into src coordinates 206cb93a386Sopenharmony_ci int sx = x - dstX + srcR.x(); 207cb93a386Sopenharmony_ci int sy = y - dstY + srcR.y(); 208cb93a386Sopenharmony_ci if (srcR.contains(sx, sy)) { 209cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, check_4x4_pixel(dstC, sx, sy)); 210cb93a386Sopenharmony_ci } else { 211cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == dstC); 212cb93a386Sopenharmony_ci } 213cb93a386Sopenharmony_ci } 214cb93a386Sopenharmony_ci } 215cb93a386Sopenharmony_ci } 216cb93a386Sopenharmony_ci } 217cb93a386Sopenharmony_ci} 218