blob: dd5bf1afde8a5ca3a72b722a3bc455acdb2cdcde [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
reed@android.com42263962009-05-01 04:00:01 +00008#include "SkBitmap.h"
reed@android.com311c82d2009-05-05 23:13:23 +00009#include "SkRect.h"
scroggo565901d2015-12-10 10:44:13 -080010#include "SkTemplates.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000011#include "Test.h"
Matt Sarett68b8e3d2017-04-28 11:15:22 -040012#include "sk_tool_utils.h"
reed@android.com42263962009-05-01 04:00:01 +000013
reed@google.com0a6151d2013-10-10 14:44:56 +000014static void init_src(const SkBitmap& bitmap) {
reed@android.com42263962009-05-01 04:00:01 +000015 if (bitmap.getPixels()) {
reed@google.com0a6151d2013-10-10 14:44:56 +000016 if (bitmap.getColorTable()) {
reed@google.com9ce6e752011-01-10 14:04:07 +000017 sk_bzero(bitmap.getPixels(), bitmap.getSize());
18 } else {
19 bitmap.eraseColor(SK_ColorWHITE);
20 }
reed@android.com42263962009-05-01 04:00:01 +000021 }
22}
23
Mike Reed6b3155c2017-04-03 14:41:44 -040024static sk_sp<SkColorTable> init_ctable() {
reed@android.com42263962009-05-01 04:00:01 +000025 static const SkColor colors[] = {
26 SK_ColorBLACK, SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE
27 };
Mike Reed6b3155c2017-04-03 14:41:44 -040028 return SkColorTable::Make(colors, SK_ARRAY_COUNT(colors));
reed@android.com42263962009-05-01 04:00:01 +000029}
30
31struct Pair {
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +000032 SkColorType fColorType;
33 const char* fValid;
reed@android.com42263962009-05-01 04:00:01 +000034};
35
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +000036// Utility functions for copyPixelsTo()/copyPixelsFrom() tests.
37// getPixel()
38// setPixel()
39// getSkConfigName()
40// struct Coordinates
41// reportCopyVerification()
42// writeCoordPixels()
43
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +000044// Helper struct to contain pixel locations, while avoiding need for STL.
45struct Coordinates {
46
47 const int length;
48 SkIPoint* const data;
49
50 explicit Coordinates(int _length): length(_length)
51 , data(new SkIPoint[length]) { }
52
53 ~Coordinates(){
54 delete [] data;
55 }
56
57 SkIPoint* operator[](int i) const {
58 // Use with care, no bounds checking.
59 return data + i;
60 }
61};
62
scroggo@google.com5ccae2c2014-01-15 16:56:52 +000063static const Pair gPairs[] = {
Matt Sarettd9836f42017-04-05 15:41:53 -040064 { kUnknown_SkColorType, "0000000" },
65 { kAlpha_8_SkColorType, "0100000" },
66 { kIndex_8_SkColorType, "0101111" },
67 { kRGB_565_SkColorType, "0101011" },
68 { kARGB_4444_SkColorType, "0101111" },
69 { kN32_SkColorType, "0101111" },
70 { kRGBA_F16_SkColorType, "0101011" },
scroggo@google.com5ccae2c2014-01-15 16:56:52 +000071};
commit-bot@chromium.org5c6f1d42014-01-10 18:28:23 +000072
scroggo@google.com5ccae2c2014-01-15 16:56:52 +000073static const int W = 20;
74static const int H = 33;
75
76static void setup_src_bitmaps(SkBitmap* srcOpaque, SkBitmap* srcPremul,
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +000077 SkColorType ct) {
Mike Reed6b3155c2017-04-03 14:41:44 -040078 sk_sp<SkColorTable> ctable;
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +000079 if (kIndex_8_SkColorType == ct) {
reedc5e15a12014-09-29 12:10:27 -070080 ctable = init_ctable();
scroggo@google.com5ccae2c2014-01-15 16:56:52 +000081 }
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +000082
Matt Sarettd9836f42017-04-05 15:41:53 -040083 sk_sp<SkColorSpace> colorSpace = nullptr;
84 if (kRGBA_F16_SkColorType == ct) {
85 colorSpace = SkColorSpace::MakeSRGBLinear();
86 }
87
88 srcOpaque->allocPixels(SkImageInfo::Make(W, H, ct, kOpaque_SkAlphaType, colorSpace), ctable);
89 srcPremul->allocPixels(SkImageInfo::Make(W, H, ct, kPremul_SkAlphaType, colorSpace), ctable);
scroggo@google.com5ccae2c2014-01-15 16:56:52 +000090 init_src(*srcOpaque);
91 init_src(*srcPremul);
92}
93
94DEF_TEST(BitmapCopy_extractSubset, reporter) {
95 for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
96 SkBitmap srcOpaque, srcPremul;
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +000097 setup_src_bitmaps(&srcOpaque, &srcPremul, gPairs[i].fColorType);
scroggo@google.com5ccae2c2014-01-15 16:56:52 +000098
99 SkBitmap bitmap(srcOpaque);
100 SkBitmap subset;
101 SkIRect r;
102 // Extract a subset which has the same width as the original. This
103 // catches a bug where we cloned the genID incorrectly.
104 r.set(0, 1, W, 3);
105 bitmap.setIsVolatile(true);
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000106 // Relies on old behavior of extractSubset failing if colortype is unknown
107 if (kUnknown_SkColorType != bitmap.colorType() && bitmap.extractSubset(&subset, r)) {
scroggo@google.com5ccae2c2014-01-15 16:56:52 +0000108 REPORTER_ASSERT(reporter, subset.width() == W);
109 REPORTER_ASSERT(reporter, subset.height() == 2);
110 REPORTER_ASSERT(reporter, subset.alphaType() == bitmap.alphaType());
111 REPORTER_ASSERT(reporter, subset.isVolatile() == true);
112
113 // Test copying an extracted subset.
114 for (size_t j = 0; j < SK_ARRAY_COUNT(gPairs); j++) {
115 SkBitmap copy;
Matt Sarett68b8e3d2017-04-28 11:15:22 -0400116 bool success = sk_tool_utils::copy_to(&copy, gPairs[j].fColorType, subset);
scroggo@google.com5ccae2c2014-01-15 16:56:52 +0000117 if (!success) {
118 // Skip checking that success matches fValid, which is redundant
119 // with the code below.
Matt Sarett03dd6d52017-01-23 12:15:09 -0500120 REPORTER_ASSERT(reporter, kIndex_8_SkColorType == gPairs[i].fColorType ||
121 gPairs[i].fColorType != gPairs[j].fColorType);
scroggo@google.com5ccae2c2014-01-15 16:56:52 +0000122 continue;
123 }
124
125 // When performing a copy of an extracted subset, the gen id should
126 // change.
127 REPORTER_ASSERT(reporter, copy.getGenerationID() != subset.getGenerationID());
128
129 REPORTER_ASSERT(reporter, copy.width() == W);
130 REPORTER_ASSERT(reporter, copy.height() == 2);
131
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000132 if (gPairs[i].fColorType == gPairs[j].fColorType) {
scroggo@google.com5ccae2c2014-01-15 16:56:52 +0000133 // they should both have, or both not-have, a colortable
halcanary96fcdcc2015-08-27 07:41:13 -0700134 bool hasCT = subset.getColorTable() != nullptr;
135 REPORTER_ASSERT(reporter, (copy.getColorTable() != nullptr) == hasCT);
scroggo@google.com5ccae2c2014-01-15 16:56:52 +0000136 }
137 }
138 }
139
140 bitmap = srcPremul;
141 bitmap.setIsVolatile(false);
142 if (bitmap.extractSubset(&subset, r)) {
143 REPORTER_ASSERT(reporter, subset.alphaType() == bitmap.alphaType());
144 REPORTER_ASSERT(reporter, subset.isVolatile() == false);
145 }
146 }
147}
148
reedb184f7f2014-07-13 04:32:32 -0700149#include "SkColorPriv.h"
150#include "SkUtils.h"
151
152/**
153 * Construct 4x4 pixels where we can look at a color and determine where it should be in the grid.
154 * alpha = 0xFF, blue = 0x80, red = x, green = y
155 */
156static void fill_4x4_pixels(SkPMColor colors[16]) {
157 for (int y = 0; y < 4; ++y) {
158 for (int x = 0; x < 4; ++x) {
159 colors[y*4+x] = SkPackARGB32(0xFF, x, y, 0x80);
160 }
161 }
162}
163
164static bool check_4x4_pixel(SkPMColor color, unsigned x, unsigned y) {
165 SkASSERT(x < 4 && y < 4);
166 return 0xFF == SkGetPackedA32(color) &&
167 x == SkGetPackedR32(color) &&
168 y == SkGetPackedG32(color) &&
169 0x80 == SkGetPackedB32(color);
170}
171
172/**
173 * Fill with all zeros, which will never match any value from fill_4x4_pixels
174 */
175static void clear_4x4_pixels(SkPMColor colors[16]) {
176 sk_memset32(colors, 0, 16);
177}
178
179// Much of readPixels is exercised by copyTo testing, since readPixels is the backend for that
180// method. Here we explicitly test subset copies.
181//
182DEF_TEST(BitmapReadPixels, reporter) {
183 const int W = 4;
184 const int H = 4;
185 const size_t rowBytes = W * sizeof(SkPMColor);
186 const SkImageInfo srcInfo = SkImageInfo::MakeN32Premul(W, H);
187 SkPMColor srcPixels[16];
188 fill_4x4_pixels(srcPixels);
189 SkBitmap srcBM;
190 srcBM.installPixels(srcInfo, srcPixels, rowBytes);
191
192 SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(W, H);
193 SkPMColor dstPixels[16];
194
195 const struct {
196 bool fExpectedSuccess;
197 SkIPoint fRequestedSrcLoc;
198 SkISize fRequestedDstSize;
199 // If fExpectedSuccess, check these, otherwise ignore
200 SkIPoint fExpectedDstLoc;
201 SkIRect fExpectedSrcR;
202 } gRec[] = {
203 { true, { 0, 0 }, { 4, 4 }, { 0, 0 }, { 0, 0, 4, 4 } },
204 { true, { 1, 1 }, { 2, 2 }, { 0, 0 }, { 1, 1, 3, 3 } },
205 { true, { 2, 2 }, { 4, 4 }, { 0, 0 }, { 2, 2, 4, 4 } },
206 { true, {-1,-1 }, { 2, 2 }, { 1, 1 }, { 0, 0, 1, 1 } },
207 { false, {-1,-1 }, { 1, 1 }, { 0, 0 }, { 0, 0, 0, 0 } },
208 };
209
210 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
211 clear_4x4_pixels(dstPixels);
212
reede5ea5002014-09-03 11:54:58 -0700213 dstInfo = dstInfo.makeWH(gRec[i].fRequestedDstSize.width(),
214 gRec[i].fRequestedDstSize.height());
reedb184f7f2014-07-13 04:32:32 -0700215 bool success = srcBM.readPixels(dstInfo, dstPixels, rowBytes,
216 gRec[i].fRequestedSrcLoc.x(), gRec[i].fRequestedSrcLoc.y());
halcanary9d524f22016-03-29 09:03:52 -0700217
reedb184f7f2014-07-13 04:32:32 -0700218 REPORTER_ASSERT(reporter, gRec[i].fExpectedSuccess == success);
219 if (success) {
220 const SkIRect srcR = gRec[i].fExpectedSrcR;
221 const int dstX = gRec[i].fExpectedDstLoc.x();
222 const int dstY = gRec[i].fExpectedDstLoc.y();
223 // Walk the dst pixels, and check if we got what we expected
224 for (int y = 0; y < H; ++y) {
225 for (int x = 0; x < W; ++x) {
226 SkPMColor dstC = dstPixels[y*4+x];
227 // get into src coordinates
228 int sx = x - dstX + srcR.x();
229 int sy = y - dstY + srcR.y();
230 if (srcR.contains(sx, sy)) {
231 REPORTER_ASSERT(reporter, check_4x4_pixel(dstC, sx, sy));
232 } else {
233 REPORTER_ASSERT(reporter, 0 == dstC);
234 }
235 }
236 }
237 }
238 }
239}