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