Flutter Engine
The Flutter Engine
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;
57 SkRandom rand;
58
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);
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);
77 }
78 }
79
80 size.set(500, 600);
81
82 const SkScalar tooMuchSubpixel = 100.1f;
83 mat.setTranslate(tooMuchSubpixel, 0);
85 mat.setTranslate(0, tooMuchSubpixel);
87
88 const SkScalar tinySubPixel = 100.02f;
89 mat.setTranslate(tinySubPixel, 0);
91 mat.setTranslate(0, tinySubPixel);
93
94 const SkScalar twoThirds = SK_Scalar1 * 2 / 3;
95 const SkScalar bigScale = (size.width() + twoThirds) / size.width();
96 mat.setScale(bigScale, bigScale);
99
100 const SkScalar oneThird = SK_Scalar1 / 3;
101 const SkScalar smallScale = (size.width() + oneThird) / size.width();
102 mat.setScale(smallScale, smallScale);
105
106 const SkScalar oneFortyth = SK_Scalar1 / 40;
107 const SkScalar tinyScale = (size.width() + oneFortyth) / size.width();
108 mat.setScale(tinyScale, tinyScale);
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
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);
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) {
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
DEF_TEST(DrawBitmapRect, reporter)
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 create(SkBitmap *bm, SkColor color)
static void rand_size(SkISize *size, SkRandom &rand)
static const TestCase gTests[]
reporter
Definition: FontMgrTest.cpp:39
int count
Definition: FontMgrTest.cpp:50
#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)
Definition: SkMatrix.cpp:1614
#define SK_Scalar1
Definition: SkScalar.h:18
#define SK_ScalarNaN
Definition: SkScalar.h:28
#define SkIntToScalar(x)
Definition: SkScalar.h:57
#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)
Definition: SkCanvas.cpp:1673
@ 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)
Definition: SkCanvas.cpp:2333
void drawPath(const SkPath &path, const SkPaint &paint)
Definition: SkCanvas.cpp:1747
void concat(const SkMatrix &matrix)
Definition: SkCanvas.cpp:1318
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
Definition: SkPath.h:59
uint32_t nextU()
Definition: SkRandom.h:42
SkScalar nextSScalar1()
Definition: SkRandom.h:113
const Paint & paint
Definition: color_source.cc:38
DlColor color
float SkScalar
Definition: extension.cpp:12
double y
double x
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
SkSamplingOptions sampling
Definition: SkRecords.h:337
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
dst
Definition: cp.py:12
int32_t height
int32_t width
Definition: SkSize.h:16
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659