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