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(&copy, 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