Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
DrawBitmapRectTest.cpp
Go to the documentation of this file.
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
11#include "include/core/SkImage.h" // IWYU pragma: keep
14#include "include/core/SkPath.h"
15#include "include/core/SkRect.h"
18#include "include/core/SkShader.h" // IWYU pragma: keep
19#include "include/core/SkSize.h"
22#include "src/base/SkRandom.h"
24#include "tests/Test.h"
25
26#include <array>
27#include <cstddef>
28#include <cstdint>
29
30///////////////////////////////////////////////////////////////////////////////
31
32static void rand_matrix(SkMatrix* mat, SkRandom& rand, unsigned mask) {
33 mat->setIdentity();
34 if (mask & SkMatrix::kTranslate_Mask) {
35 mat->postTranslate(rand.nextSScalar1(), rand.nextSScalar1());
36 }
37 if (mask & SkMatrix::kScale_Mask) {
38 mat->postScale(rand.nextSScalar1(), rand.nextSScalar1());
39 }
40 if (mask & SkMatrix::kAffine_Mask) {
41 mat->postRotate(rand.nextSScalar1() * 360);
42 }
43 if (mask & SkMatrix::kPerspective_Mask) {
44 mat->setPerspX(rand.nextSScalar1());
45 mat->setPerspY(rand.nextSScalar1());
46 }
47}
48
49static void rand_size(SkISize* size, SkRandom& rand) {
50 size->set(rand.nextU() & 0xFFFF, rand.nextU() & 0xFFFF);
51}
52
54
55 SkMatrix mat;
56 SkISize size;
57 SkRandom rand;
58
59 const SkSamplingOptions sampling;
60
61 // assert: translate-only no-aa can always be treated as sprite
62 for (int i = 0; i < 1000; ++i) {
64 for (int j = 0; j < 1000; ++j) {
65 rand_size(&size, rand);
66 REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, sampling, false));
67 }
68 }
69
70 // assert: rotate/perspect is never treated as sprite
71 for (int i = 0; i < 1000; ++i) {
73 for (int j = 0; j < 1000; ++j) {
74 rand_size(&size, rand);
75 REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, sampling, false));
76 REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, sampling, true));
77 }
78 }
79
80 size.set(500, 600);
81
82 const SkScalar tooMuchSubpixel = 100.1f;
83 mat.setTranslate(tooMuchSubpixel, 0);
84 REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, sampling, true));
85 mat.setTranslate(0, tooMuchSubpixel);
86 REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, sampling, true));
87
88 const SkScalar tinySubPixel = 100.02f;
89 mat.setTranslate(tinySubPixel, 0);
90 REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, sampling, true));
91 mat.setTranslate(0, tinySubPixel);
92 REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, sampling, true));
93
94 const SkScalar twoThirds = SK_Scalar1 * 2 / 3;
95 const SkScalar bigScale = (size.width() + twoThirds) / size.width();
96 mat.setScale(bigScale, bigScale);
97 REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, sampling, false));
98 REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, sampling, true));
99
100 const SkScalar oneThird = SK_Scalar1 / 3;
101 const SkScalar smallScale = (size.width() + oneThird) / size.width();
102 mat.setScale(smallScale, smallScale);
103 REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, sampling, false));
104 REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, sampling, true));
105
106 const SkScalar oneFortyth = SK_Scalar1 / 40;
107 const SkScalar tinyScale = (size.width() + oneFortyth) / size.width();
108 mat.setScale(tinyScale, tinyScale);
109 REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, sampling, false));
110 REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, sampling, true));
111}
112
114 int width, int height) {
115 SkBitmap dev;
116 dev.allocN32Pixels(0x56F, 0x4f6);
117 dev.eraseColor(SK_ColorTRANSPARENT); // necessary, so we know if we draw to it
118
119 SkMatrix matrix;
120
121 SkCanvas c(dev);
122 matrix.setAll(-119.34097f,
123 -43.436558f,
124 93489.945f,
125 43.436558f,
126 -119.34097f,
127 123.98426f,
128 0, 0, SK_Scalar1);
129 c.concat(matrix);
130
131 SkBitmap bm;
132 if (bm.tryAllocN32Pixels(width, height)) {
134 } else {
135 SkASSERT(false);
136 return;
137 }
138
139 matrix.setAll(0.0078740157f,
140 0,
141 SkIntToScalar(249),
142 0,
143 0.0078740157f,
144 SkIntToScalar(239),
145 0, 0, SK_Scalar1);
148 SkSamplingOptions(), matrix));
149
150 SkRect r = SkRect::MakeXYWH(681, 239, 695, 253);
151 c.drawRect(r, paint);
152
153 for (int y = 0; y < dev.height(); ++y) {
154 for (int x = 0; x < dev.width(); ++x) {
155 if (SK_ColorTRANSPARENT == *dev.getAddr32(x, y)) {
157 return;
158 }
159 }
160 }
161}
162
163// ATTENTION We should always draw each of these sizes safely now. ATTENTION
164// ATTENTION I'm leaving this next /*comment*/ for posterity. ATTENTION
165
166/*
167 * Original bug was asserting that the matrix-proc had generated a (Y) value
168 * that was out of range. This led (in the release build) to the sampler-proc
169 * reading memory out-of-bounds of the original bitmap.
170 *
171 * We were numerically overflowing our 16bit coordinates that we communicate
172 * between these two procs. The fixes was in two parts:
173 *
174 * 1. Just don't draw bitmaps larger than 64K-1 in width or height, since we
175 * can't represent those coordinates in our transport format (yet).
176 * 2. Perform an unsigned shift during the calculation, so we don't get
177 * sign-extension bleed when packing the two values (X,Y) into our 32bit
178 * slot.
179 *
180 * This tests exercises the original setup, plus 2 more to ensure that we can,
181 * in fact, handle bitmaps at 64K-1 (assuming we don't exceed the total
182 * memory allocation limit).
183 */
185 static const struct {
186 int fWidth;
187 int fHeight;
188 } gTests[] = {
189 { 0x1b294, 0x7f}, // crbug 118018 (width exceeds 64K)... should draw safely now.
190 { 0xFFFF, 0x7f }, // should draw, test max width
191 { 0x7f, 0xFFFF }, // should draw, test max height
192 };
193
194 for (size_t i = 0; i < std::size(gTests); ++i) {
196 gTests[i].fWidth, gTests[i].fHeight);
197 }
198}
199
200///////////////////////////////////////////////////////////////////////////////
201
202static void test_nan_antihair() {
203 SkBitmap bm;
204 bm.allocN32Pixels(20, 20);
205
206 SkCanvas canvas(bm);
207
208 SkPath path;
209 path.moveTo(0, 0);
210 path.lineTo(10, SK_ScalarNaN);
211
213 paint.setAntiAlias(true);
215
216 // before our fix to SkScan_Antihair.cpp to check for integral NaN (0x800...)
217 // this would trigger an assert/crash.
218 //
219 // see rev. 3558
220 canvas.drawPath(path, paint);
221}
222
223static bool check_for_all_zeros(const SkBitmap& bm) {
224 size_t count = bm.width() * bm.bytesPerPixel();
225 for (int y = 0; y < bm.height(); y++) {
226 const uint8_t* ptr = reinterpret_cast<const uint8_t*>(bm.getAddr(0, y));
227 for (size_t i = 0; i < count; i++) {
228 if (ptr[i]) {
229 return false;
230 }
231 }
232 }
233 return true;
234}
235
236static const int gWidth = 256;
237static const int gHeight = 256;
238
239static void create(SkBitmap* bm, SkColor color) {
241 bm->eraseColor(color);
242}
243
244DEF_TEST(DrawBitmapRect, reporter) {
245 SkBitmap src, dst;
246
247 create(&src, 0xFFFFFFFF);
248 create(&dst, 0);
249
250 SkCanvas canvas(dst);
251
252 SkRect srcR = { gWidth, 0, gWidth + 16, 16 };
253 SkRect dstR = { 0, 0, 16, 16 };
254
255 canvas.drawImageRect(src.asImage(), srcR, dstR, SkSamplingOptions(), nullptr,
257
258 // ensure that we draw nothing if srcR does not intersect the bitmap
260
263
265}
static void rand_matrix(SkMatrix *mat, SkRandom &rand, unsigned mask)
static void test_nan_antihair()
static const int gWidth
static bool check_for_all_zeros(const SkBitmap &bm)
static void test_wacky_bitmapshader(skiatest::Reporter *reporter, int width, int height)
static const int gHeight
static void test_giantrepeat_crbug118018(skiatest::Reporter *reporter)
static void test_treatAsSprite(skiatest::Reporter *reporter)
static void rand_size(SkISize *size, SkRandom &rand)
static const TestCase gTests[]
reporter
int count
SkColor4f color
#define SkASSERT(cond)
Definition SkAssert.h:116
uint32_t SkColor
Definition SkColor.h:37
constexpr SkColor SK_ColorTRANSPARENT
Definition SkColor.h:99
constexpr SkColor SK_ColorRED
Definition SkColor.h:126
bool SkTreatAsSprite(const SkMatrix &mat, const SkISize &size, const SkSamplingOptions &sampling, bool isAntiAlias)
#define SK_Scalar1
Definition SkScalar.h:18
#define SK_ScalarNaN
Definition SkScalar.h:28
#define SkIntToScalar(x)
Definition SkScalar.h:57
#define DEF_TEST(name, reporter)
Definition Test.h:312
#define REPORTER_ASSERT(r, cond,...)
Definition Test.h:286
int width() const
Definition SkBitmap.h:149
void * getAddr(int x, int y) const
Definition SkBitmap.cpp:406
sk_sp< SkShader > makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &, const SkMatrix *localMatrix=nullptr) const
Definition SkBitmap.cpp:669
int bytesPerPixel() const
Definition SkBitmap.h:187
void allocN32Pixels(int width, int height, bool isOpaque=false)
Definition SkBitmap.cpp:232
int height() const
Definition SkBitmap.h:158
uint32_t * getAddr32(int x, int y) const
Definition SkBitmap.h:1260
bool tryAllocN32Pixels(int width, int height, bool isOpaque=false)
Definition SkBitmap.cpp:226
void eraseColor(SkColor4f) const
Definition SkBitmap.cpp:442
void drawRect(const SkRect &rect, const SkPaint &paint)
@ kStrict_SrcRectConstraint
sample only inside bounds; slower
Definition SkCanvas.h:1542
void drawImageRect(const SkImage *, const SkRect &src, const SkRect &dst, const SkSamplingOptions &, const SkPaint *, SrcRectConstraint)
void drawPath(const SkPath &path, const SkPaint &paint)
void concat(const SkMatrix &matrix)
SkMatrix & postTranslate(SkScalar dx, SkScalar dy)
Definition SkMatrix.cpp:281
SkMatrix & postRotate(SkScalar degrees, SkScalar px, SkScalar py)
Definition SkMatrix.cpp:474
SkMatrix & postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
Definition SkMatrix.cpp:360
SkMatrix & setPerspX(SkScalar v)
Definition SkMatrix.h:537
SkMatrix & setTranslate(SkScalar dx, SkScalar dy)
Definition SkMatrix.cpp:254
SkMatrix & setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
Definition SkMatrix.cpp:296
SkMatrix & setPerspY(SkScalar v)
Definition SkMatrix.h:544
SkMatrix & setIdentity()
Definition SkMatrix.h:626
@ kPerspective_Mask
perspective SkMatrix
Definition SkMatrix.h:196
@ kTranslate_Mask
translation SkMatrix
Definition SkMatrix.h:193
@ kScale_Mask
scale SkMatrix
Definition SkMatrix.h:194
@ kAffine_Mask
skew or rotate SkMatrix
Definition SkMatrix.h:195
@ kStroke_Style
set to stroke geometry
Definition SkPaint.h:194
uint32_t nextU()
Definition SkRandom.h:42
SkScalar nextSScalar1()
Definition SkRandom.h:113
const Paint & paint
float SkScalar
Definition extension.cpp:12
double y
double x
int32_t height
int32_t width
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition SkRect.h:659