blob: e960df805b2743df0b682074e67241edccb81e11 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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 */
commit-bot@chromium.org8ef51b92014-03-05 13:43:15 +00007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#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 "tests/Test.h"
18#include "tools/ToolUtils.h"
reed@android.com42263962009-05-01 04:00:01 +000019
reed@google.com0a6151d2013-10-10 14:44:56 +000020static void init_src(const SkBitmap& bitmap) {
reed@android.com42263962009-05-01 04:00:01 +000021 if (bitmap.getPixels()) {
Mike Reed086a4272017-07-18 10:53:11 -040022 bitmap.eraseColor(SK_ColorWHITE);
reed@android.com42263962009-05-01 04:00:01 +000023 }
24}
25
reed@android.com42263962009-05-01 04:00:01 +000026struct Pair {
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +000027 SkColorType fColorType;
28 const char* fValid;
reed@android.com42263962009-05-01 04:00:01 +000029};
30
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +000031// Utility functions for copyPixelsTo()/copyPixelsFrom() tests.
32// getPixel()
33// setPixel()
34// getSkConfigName()
35// struct Coordinates
36// reportCopyVerification()
37// writeCoordPixels()
38
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +000039// Helper struct to contain pixel locations, while avoiding need for STL.
40struct Coordinates {
41
42 const int length;
43 SkIPoint* const data;
44
45 explicit Coordinates(int _length): length(_length)
46 , data(new SkIPoint[length]) { }
47
48 ~Coordinates(){
49 delete [] data;
50 }
51
52 SkIPoint* operator[](int i) const {
53 // Use with care, no bounds checking.
54 return data + i;
55 }
56};
57
scroggo@google.com5ccae2c2014-01-15 16:56:52 +000058static const Pair gPairs[] = {
Matt Sarettd9836f42017-04-05 15:41:53 -040059 { kUnknown_SkColorType, "0000000" },
60 { kAlpha_8_SkColorType, "0100000" },
Matt Sarettd9836f42017-04-05 15:41:53 -040061 { kRGB_565_SkColorType, "0101011" },
62 { kARGB_4444_SkColorType, "0101111" },
63 { kN32_SkColorType, "0101111" },
64 { kRGBA_F16_SkColorType, "0101011" },
scroggo@google.com5ccae2c2014-01-15 16:56:52 +000065};
commit-bot@chromium.org5c6f1d42014-01-10 18:28:23 +000066
scroggo@google.com5ccae2c2014-01-15 16:56:52 +000067static const int W = 20;
68static const int H = 33;
69
70static void setup_src_bitmaps(SkBitmap* srcOpaque, SkBitmap* srcPremul,
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +000071 SkColorType ct) {
Matt Sarettd9836f42017-04-05 15:41:53 -040072 sk_sp<SkColorSpace> colorSpace = nullptr;
73 if (kRGBA_F16_SkColorType == ct) {
Brian Osman6b622962018-08-27 19:16:02 +000074 colorSpace = SkColorSpace::MakeSRGB();
Matt Sarettd9836f42017-04-05 15:41:53 -040075 }
76
Mike Reed304a07c2017-07-12 15:10:28 -040077 srcOpaque->allocPixels(SkImageInfo::Make(W, H, ct, kOpaque_SkAlphaType, colorSpace));
78 srcPremul->allocPixels(SkImageInfo::Make(W, H, ct, kPremul_SkAlphaType, colorSpace));
scroggo@google.com5ccae2c2014-01-15 16:56:52 +000079 init_src(*srcOpaque);
80 init_src(*srcPremul);
81}
82
83DEF_TEST(BitmapCopy_extractSubset, reporter) {
84 for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
85 SkBitmap srcOpaque, srcPremul;
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +000086 setup_src_bitmaps(&srcOpaque, &srcPremul, gPairs[i].fColorType);
scroggo@google.com5ccae2c2014-01-15 16:56:52 +000087
88 SkBitmap bitmap(srcOpaque);
89 SkBitmap subset;
90 SkIRect r;
91 // Extract a subset which has the same width as the original. This
92 // catches a bug where we cloned the genID incorrectly.
Mike Reed92b33352019-08-24 19:39:13 -040093 r.setLTRB(0, 1, W, 3);
scroggo@google.com5ccae2c2014-01-15 16:56:52 +000094 bitmap.setIsVolatile(true);
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +000095 // Relies on old behavior of extractSubset failing if colortype is unknown
96 if (kUnknown_SkColorType != bitmap.colorType() && bitmap.extractSubset(&subset, r)) {
scroggo@google.com5ccae2c2014-01-15 16:56:52 +000097 REPORTER_ASSERT(reporter, subset.width() == W);
98 REPORTER_ASSERT(reporter, subset.height() == 2);
99 REPORTER_ASSERT(reporter, subset.alphaType() == bitmap.alphaType());
100 REPORTER_ASSERT(reporter, subset.isVolatile() == true);
101
102 // Test copying an extracted subset.
103 for (size_t j = 0; j < SK_ARRAY_COUNT(gPairs); j++) {
104 SkBitmap copy;
Mike Kleinea3f0142019-03-20 11:12:10 -0500105 bool success = ToolUtils::copy_to(&copy, gPairs[j].fColorType, subset);
scroggo@google.com5ccae2c2014-01-15 16:56:52 +0000106 if (!success) {
107 // Skip checking that success matches fValid, which is redundant
108 // with the code below.
Mike Reed304a07c2017-07-12 15:10:28 -0400109 REPORTER_ASSERT(reporter, gPairs[i].fColorType != gPairs[j].fColorType);
scroggo@google.com5ccae2c2014-01-15 16:56:52 +0000110 continue;
111 }
112
113 // When performing a copy of an extracted subset, the gen id should
114 // change.
115 REPORTER_ASSERT(reporter, copy.getGenerationID() != subset.getGenerationID());
116
117 REPORTER_ASSERT(reporter, copy.width() == W);
118 REPORTER_ASSERT(reporter, copy.height() == 2);
scroggo@google.com5ccae2c2014-01-15 16:56:52 +0000119 }
120 }
121
122 bitmap = srcPremul;
123 bitmap.setIsVolatile(false);
124 if (bitmap.extractSubset(&subset, r)) {
125 REPORTER_ASSERT(reporter, subset.alphaType() == bitmap.alphaType());
126 REPORTER_ASSERT(reporter, subset.isVolatile() == false);
127 }
128 }
129}
130
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500131#include "include/core/SkColorPriv.h"
132#include "src/core/SkUtils.h"
reedb184f7f2014-07-13 04:32:32 -0700133
134/**
135 * Construct 4x4 pixels where we can look at a color and determine where it should be in the grid.
136 * alpha = 0xFF, blue = 0x80, red = x, green = y
137 */
138static void fill_4x4_pixels(SkPMColor colors[16]) {
139 for (int y = 0; y < 4; ++y) {
140 for (int x = 0; x < 4; ++x) {
141 colors[y*4+x] = SkPackARGB32(0xFF, x, y, 0x80);
142 }
143 }
144}
145
146static bool check_4x4_pixel(SkPMColor color, unsigned x, unsigned y) {
147 SkASSERT(x < 4 && y < 4);
148 return 0xFF == SkGetPackedA32(color) &&
149 x == SkGetPackedR32(color) &&
150 y == SkGetPackedG32(color) &&
151 0x80 == SkGetPackedB32(color);
152}
153
154/**
155 * Fill with all zeros, which will never match any value from fill_4x4_pixels
156 */
157static void clear_4x4_pixels(SkPMColor colors[16]) {
158 sk_memset32(colors, 0, 16);
159}
160
161// Much of readPixels is exercised by copyTo testing, since readPixels is the backend for that
162// method. Here we explicitly test subset copies.
163//
164DEF_TEST(BitmapReadPixels, reporter) {
165 const int W = 4;
166 const int H = 4;
167 const size_t rowBytes = W * sizeof(SkPMColor);
168 const SkImageInfo srcInfo = SkImageInfo::MakeN32Premul(W, H);
169 SkPMColor srcPixels[16];
170 fill_4x4_pixels(srcPixels);
171 SkBitmap srcBM;
172 srcBM.installPixels(srcInfo, srcPixels, rowBytes);
173
174 SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(W, H);
175 SkPMColor dstPixels[16];
176
177 const struct {
178 bool fExpectedSuccess;
179 SkIPoint fRequestedSrcLoc;
180 SkISize fRequestedDstSize;
181 // If fExpectedSuccess, check these, otherwise ignore
182 SkIPoint fExpectedDstLoc;
183 SkIRect fExpectedSrcR;
184 } gRec[] = {
185 { true, { 0, 0 }, { 4, 4 }, { 0, 0 }, { 0, 0, 4, 4 } },
186 { true, { 1, 1 }, { 2, 2 }, { 0, 0 }, { 1, 1, 3, 3 } },
187 { true, { 2, 2 }, { 4, 4 }, { 0, 0 }, { 2, 2, 4, 4 } },
188 { true, {-1,-1 }, { 2, 2 }, { 1, 1 }, { 0, 0, 1, 1 } },
189 { false, {-1,-1 }, { 1, 1 }, { 0, 0 }, { 0, 0, 0, 0 } },
190 };
191
192 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
193 clear_4x4_pixels(dstPixels);
194
Brian Salomon9241a6d2019-10-03 13:26:54 -0400195 dstInfo = dstInfo.makeDimensions(gRec[i].fRequestedDstSize);
reedb184f7f2014-07-13 04:32:32 -0700196 bool success = srcBM.readPixels(dstInfo, dstPixels, rowBytes,
197 gRec[i].fRequestedSrcLoc.x(), gRec[i].fRequestedSrcLoc.y());
halcanary9d524f22016-03-29 09:03:52 -0700198
reedb184f7f2014-07-13 04:32:32 -0700199 REPORTER_ASSERT(reporter, gRec[i].fExpectedSuccess == success);
200 if (success) {
201 const SkIRect srcR = gRec[i].fExpectedSrcR;
202 const int dstX = gRec[i].fExpectedDstLoc.x();
203 const int dstY = gRec[i].fExpectedDstLoc.y();
204 // Walk the dst pixels, and check if we got what we expected
205 for (int y = 0; y < H; ++y) {
206 for (int x = 0; x < W; ++x) {
207 SkPMColor dstC = dstPixels[y*4+x];
208 // get into src coordinates
209 int sx = x - dstX + srcR.x();
210 int sy = y - dstY + srcR.y();
211 if (srcR.contains(sx, sy)) {
212 REPORTER_ASSERT(reporter, check_4x4_pixel(dstC, sx, sy));
213 } else {
214 REPORTER_ASSERT(reporter, 0 == dstC);
215 }
216 }
217 }
218 }
219 }
220}