• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 #include "SkBitmap.h"
9 #include "SkCanvas.h"
10 #include "SkData.h"
11 #include "SkDiscardableMemoryPool.h"
12 #include "SkImageGenerator.h"
13 #include "SkMatrixUtils.h"
14 #include "SkPaint.h"
15 #include "SkPath.h"
16 #include "SkPixelRef.h"
17 #include "SkRandom.h"
18 #include "SkShader.h"
19 #include "SkSurface.h"
20 #include "Test.h"
21 
22 ///////////////////////////////////////////////////////////////////////////////
23 
rand_matrix(SkMatrix * mat,SkRandom & rand,unsigned mask)24 static void rand_matrix(SkMatrix* mat, SkRandom& rand, unsigned mask) {
25     mat->setIdentity();
26     if (mask & SkMatrix::kTranslate_Mask) {
27         mat->postTranslate(rand.nextSScalar1(), rand.nextSScalar1());
28     }
29     if (mask & SkMatrix::kScale_Mask) {
30         mat->postScale(rand.nextSScalar1(), rand.nextSScalar1());
31     }
32     if (mask & SkMatrix::kAffine_Mask) {
33         mat->postRotate(rand.nextSScalar1() * 360);
34     }
35     if (mask & SkMatrix::kPerspective_Mask) {
36         mat->setPerspX(rand.nextSScalar1());
37         mat->setPerspY(rand.nextSScalar1());
38     }
39 }
40 
rand_size(SkISize * size,SkRandom & rand)41 static void rand_size(SkISize* size, SkRandom& rand) {
42     size->set(rand.nextU() & 0xFFFF, rand.nextU() & 0xFFFF);
43 }
44 
test_treatAsSprite(skiatest::Reporter * reporter)45 static void test_treatAsSprite(skiatest::Reporter* reporter) {
46 
47     SkMatrix mat;
48     SkISize  size;
49     SkRandom rand;
50 
51     SkPaint noaaPaint;
52     SkPaint aaPaint;
53     aaPaint.setAntiAlias(true);
54 
55     // assert: translate-only no-aa can always be treated as sprite
56     for (int i = 0; i < 1000; ++i) {
57         rand_matrix(&mat, rand, SkMatrix::kTranslate_Mask);
58         for (int j = 0; j < 1000; ++j) {
59             rand_size(&size, rand);
60             REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, noaaPaint));
61         }
62     }
63 
64     // assert: rotate/perspect is never treated as sprite
65     for (int i = 0; i < 1000; ++i) {
66         rand_matrix(&mat, rand, SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask);
67         for (int j = 0; j < 1000; ++j) {
68             rand_size(&size, rand);
69             REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, noaaPaint));
70             REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, aaPaint));
71         }
72     }
73 
74     size.set(500, 600);
75 
76     const SkScalar tooMuchSubpixel = 100.1f;
77     mat.setTranslate(tooMuchSubpixel, 0);
78     REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, aaPaint));
79     mat.setTranslate(0, tooMuchSubpixel);
80     REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, aaPaint));
81 
82     const SkScalar tinySubPixel = 100.02f;
83     mat.setTranslate(tinySubPixel, 0);
84     REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, aaPaint));
85     mat.setTranslate(0, tinySubPixel);
86     REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, aaPaint));
87 
88     const SkScalar twoThirds = SK_Scalar1 * 2 / 3;
89     const SkScalar bigScale = (size.width() + twoThirds) / size.width();
90     mat.setScale(bigScale, bigScale);
91     REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, noaaPaint));
92     REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, aaPaint));
93 
94     const SkScalar oneThird = SK_Scalar1 / 3;
95     const SkScalar smallScale = (size.width() + oneThird) / size.width();
96     mat.setScale(smallScale, smallScale);
97     REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, noaaPaint));
98     REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, aaPaint));
99 
100     const SkScalar oneFortyth = SK_Scalar1 / 40;
101     const SkScalar tinyScale = (size.width() + oneFortyth) / size.width();
102     mat.setScale(tinyScale, tinyScale);
103     REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, noaaPaint));
104     REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, aaPaint));
105 }
106 
assert_ifDrawnTo(skiatest::Reporter * reporter,const SkBitmap & bm,bool shouldBeDrawn)107 static void assert_ifDrawnTo(skiatest::Reporter* reporter,
108                              const SkBitmap& bm, bool shouldBeDrawn) {
109     for (int y = 0; y < bm.height(); ++y) {
110         for (int x = 0; x < bm.width(); ++x) {
111             if (shouldBeDrawn) {
112                 if (SK_ColorTRANSPARENT == *bm.getAddr32(x, y)) {
113                     REPORTER_ASSERT(reporter, false);
114                     return;
115                 }
116             } else {
117                 // should not be drawn
118                 if (SK_ColorTRANSPARENT != *bm.getAddr32(x, y)) {
119                     REPORTER_ASSERT(reporter, false);
120                     return;
121                 }
122             }
123         }
124     }
125 }
126 
test_wacky_bitmapshader(skiatest::Reporter * reporter,int width,int height,bool shouldBeDrawn)127 static void test_wacky_bitmapshader(skiatest::Reporter* reporter,
128                                     int width, int height, bool shouldBeDrawn) {
129     SkBitmap dev;
130     dev.allocN32Pixels(0x56F, 0x4f6);
131     dev.eraseColor(SK_ColorTRANSPARENT);  // necessary, so we know if we draw to it
132 
133     SkMatrix matrix;
134 
135     SkCanvas c(dev);
136     matrix.setAll(-119.34097f,
137                   -43.436558f,
138                   93489.945f,
139                   43.436558f,
140                   -119.34097f,
141                   123.98426f,
142                   0, 0, SK_Scalar1);
143     c.concat(matrix);
144 
145     SkBitmap bm;
146     if (bm.tryAllocN32Pixels(width, height)) {
147         // allow this to fail silently, to test the code downstream
148     }
149     bm.eraseColor(SK_ColorRED);
150 
151     matrix.setAll(0.0078740157f,
152                   0,
153                   SkIntToScalar(249),
154                   0,
155                   0.0078740157f,
156                   SkIntToScalar(239),
157                   0, 0, SK_Scalar1);
158     SkPaint paint;
159     paint.setShader(SkShader::MakeBitmapShader(bm, SkShader::kRepeat_TileMode,
160                                                SkShader::kRepeat_TileMode, &matrix));
161 
162     SkRect r = SkRect::MakeXYWH(681, 239, 695, 253);
163     c.drawRect(r, paint);
164 
165     assert_ifDrawnTo(reporter, dev, shouldBeDrawn);
166 }
167 
168 /*
169  *  Original bug was asserting that the matrix-proc had generated a (Y) value
170  *  that was out of range. This led (in the release build) to the sampler-proc
171  *  reading memory out-of-bounds of the original bitmap.
172  *
173  *  We were numerically overflowing our 16bit coordinates that we communicate
174  *  between these two procs. The fixes was in two parts:
175  *
176  *  1. Just don't draw bitmaps larger than 64K-1 in width or height, since we
177  *     can't represent those coordinates in our transport format (yet).
178  *  2. Perform an unsigned shift during the calculation, so we don't get
179  *     sign-extension bleed when packing the two values (X,Y) into our 32bit
180  *     slot.
181  *
182  *  This tests exercises the original setup, plus 3 more to ensure that we can,
183  *  in fact, handle bitmaps at 64K-1 (assuming we don't exceed the total
184  *  memory allocation limit).
185  */
test_giantrepeat_crbug118018(skiatest::Reporter * reporter)186 static void test_giantrepeat_crbug118018(skiatest::Reporter* reporter) {
187     static const struct {
188         int fWidth;
189         int fHeight;
190         bool fExpectedToDraw;
191     } gTests[] = {
192         { 0x1b294, 0x7f,  false },   // crbug 118018 (width exceeds 64K)
193         { 0xFFFF, 0x7f,    true },   // should draw, test max width
194         { 0x7f, 0xFFFF,    true },   // should draw, test max height
195         { 0xFFFF, 0xFFFF, false },   // allocation fails (too much RAM)
196     };
197 
198     for (size_t i = 0; i < SK_ARRAY_COUNT(gTests); ++i) {
199         test_wacky_bitmapshader(reporter,
200                                 gTests[i].fWidth, gTests[i].fHeight,
201                                 gTests[i].fExpectedToDraw);
202     }
203 }
204 
205 ///////////////////////////////////////////////////////////////////////////////
206 
test_nan_antihair()207 static void test_nan_antihair() {
208     SkBitmap bm;
209     bm.allocN32Pixels(20, 20);
210 
211     SkCanvas canvas(bm);
212 
213     SkPath path;
214     path.moveTo(0, 0);
215     path.lineTo(10, SK_ScalarNaN);
216 
217     SkPaint paint;
218     paint.setAntiAlias(true);
219     paint.setStyle(SkPaint::kStroke_Style);
220 
221     // before our fix to SkScan_Antihair.cpp to check for integral NaN (0x800...)
222     // this would trigger an assert/crash.
223     //
224     // see rev. 3558
225     canvas.drawPath(path, paint);
226 }
227 
check_for_all_zeros(const SkBitmap & bm)228 static bool check_for_all_zeros(const SkBitmap& bm) {
229     size_t count = bm.width() * bm.bytesPerPixel();
230     for (int y = 0; y < bm.height(); y++) {
231         const uint8_t* ptr = reinterpret_cast<const uint8_t*>(bm.getAddr(0, y));
232         for (size_t i = 0; i < count; i++) {
233             if (ptr[i]) {
234                 return false;
235             }
236         }
237     }
238     return true;
239 }
240 
241 static const int gWidth = 256;
242 static const int gHeight = 256;
243 
create(SkBitmap * bm,SkColor color)244 static void create(SkBitmap* bm, SkColor color) {
245     bm->allocN32Pixels(gWidth, gHeight);
246     bm->eraseColor(color);
247 }
248 
DEF_TEST(DrawBitmapRect,reporter)249 DEF_TEST(DrawBitmapRect, reporter) {
250     SkBitmap src, dst;
251 
252     create(&src, 0xFFFFFFFF);
253     create(&dst, 0);
254 
255     SkCanvas canvas(dst);
256 
257     SkIRect srcR = { gWidth, 0, gWidth + 16, 16 };
258     SkRect  dstR = { 0, 0, SkIntToScalar(16), SkIntToScalar(16) };
259 
260     canvas.drawBitmapRect(src, srcR, dstR, nullptr);
261 
262     // ensure that we draw nothing if srcR does not intersect the bitmap
263     REPORTER_ASSERT(reporter, check_for_all_zeros(dst));
264 
265     test_nan_antihair();
266     test_giantrepeat_crbug118018(reporter);
267 
268     test_treatAsSprite(reporter);
269 }
270