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