Home | History | Annotate | Download | only in core
      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 "SkBitmapProcShader.h"
      9 #include "SkBitmapProcState.h"
     10 #include "SkBitmapProvider.h"
     11 #include "SkColorPriv.h"
     12 #include "SkErrorInternals.h"
     13 #include "SkPixelRef.h"
     14 #include "SkReadBuffer.h"
     15 #include "SkWriteBuffer.h"
     16 
     17 #if SK_SUPPORT_GPU
     18 #include "SkGrPriv.h"
     19 #include "effects/GrBicubicEffect.h"
     20 #include "effects/GrSimpleTextureEffect.h"
     21 #endif
     22 
     23 size_t SkBitmapProcShader::ContextSize() {
     24     // The SkBitmapProcState is stored outside of the context object, with the context holding
     25     // a pointer to it.
     26     return sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState);
     27 }
     28 
     29 SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, TileMode tmx, TileMode tmy,
     30                                        const SkMatrix* localMatrix)
     31         : INHERITED(localMatrix) {
     32     fRawBitmap = src;
     33     fTileModeX = (uint8_t)tmx;
     34     fTileModeY = (uint8_t)tmy;
     35 }
     36 
     37 bool SkBitmapProcShader::onIsABitmap(SkBitmap* texture, SkMatrix* texM, TileMode xy[]) const {
     38     if (texture) {
     39         *texture = fRawBitmap;
     40     }
     41     if (texM) {
     42         texM->reset();
     43     }
     44     if (xy) {
     45         xy[0] = (TileMode)fTileModeX;
     46         xy[1] = (TileMode)fTileModeY;
     47     }
     48     return true;
     49 }
     50 
     51 SkFlattenable* SkBitmapProcShader::CreateProc(SkReadBuffer& buffer) {
     52     SkMatrix lm;
     53     buffer.readMatrix(&lm);
     54     SkBitmap bm;
     55     if (!buffer.readBitmap(&bm)) {
     56         return nullptr;
     57     }
     58     bm.setImmutable();
     59     TileMode mx = (TileMode)buffer.readUInt();
     60     TileMode my = (TileMode)buffer.readUInt();
     61     return SkShader::CreateBitmapShader(bm, mx, my, &lm);
     62 }
     63 
     64 void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const {
     65     buffer.writeMatrix(this->getLocalMatrix());
     66     buffer.writeBitmap(fRawBitmap);
     67     buffer.writeUInt(fTileModeX);
     68     buffer.writeUInt(fTileModeY);
     69 }
     70 
     71 bool SkBitmapProcShader::isOpaque() const {
     72     return fRawBitmap.isOpaque();
     73 }
     74 
     75 SkShader::Context* SkBitmapProcShader::MakeContext(const SkShader& shader,
     76                                                    TileMode tmx, TileMode tmy,
     77                                                    const SkBitmapProvider& provider,
     78                                                    const ContextRec& rec, void* storage) {
     79     SkMatrix totalInverse;
     80     // Do this first, so we know the matrix can be inverted.
     81     if (!shader.computeTotalInverse(rec, &totalInverse)) {
     82         return nullptr;
     83     }
     84 
     85     void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext);
     86     SkBitmapProcState* state = new (stateStorage) SkBitmapProcState(provider, tmx, tmy);
     87 
     88     SkASSERT(state);
     89     if (!state->chooseProcs(totalInverse, *rec.fPaint)) {
     90         state->~SkBitmapProcState();
     91         return nullptr;
     92     }
     93 
     94     return new (storage) BitmapProcShaderContext(shader, rec, state);
     95 }
     96 
     97 SkShader::Context* SkBitmapProcShader::onCreateContext(const ContextRec& rec, void* storage) const {
     98     return MakeContext(*this, (TileMode)fTileModeX, (TileMode)fTileModeY,
     99                        SkBitmapProvider(fRawBitmap), rec, storage);
    100 }
    101 
    102 static bool only_scale_and_translate(const SkMatrix& matrix) {
    103     unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
    104     return (matrix.getType() & ~mask) == 0;
    105 }
    106 
    107 SkBitmapProcShader::BitmapProcShaderContext::BitmapProcShaderContext(const SkShader& shader,
    108                                                                      const ContextRec& rec,
    109                                                                      SkBitmapProcState* state)
    110     : INHERITED(shader, rec)
    111     , fState(state)
    112 {
    113     fFlags = 0;
    114     if (fState->fPixmap.isOpaque() && (255 == this->getPaintAlpha())) {
    115         fFlags |= kOpaqueAlpha_Flag;
    116     }
    117 
    118     if (1 == fState->fPixmap.height() && only_scale_and_translate(this->getTotalInverse())) {
    119         fFlags |= kConstInY32_Flag;
    120     }
    121 }
    122 
    123 SkBitmapProcShader::BitmapProcShaderContext::~BitmapProcShaderContext() {
    124     // The bitmap proc state has been created outside of the context on memory that will be freed
    125     // elsewhere. Only call the destructor but leave the freeing of the memory to the caller.
    126     fState->~SkBitmapProcState();
    127 }
    128 
    129 #define BUF_MAX     128
    130 
    131 #define TEST_BUFFER_OVERRITEx
    132 
    133 #ifdef TEST_BUFFER_OVERRITE
    134     #define TEST_BUFFER_EXTRA   32
    135     #define TEST_PATTERN    0x88888888
    136 #else
    137     #define TEST_BUFFER_EXTRA   0
    138 #endif
    139 
    140 void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan(int x, int y, SkPMColor dstC[],
    141                                                             int count) {
    142     const SkBitmapProcState& state = *fState;
    143     if (state.getShaderProc32()) {
    144         state.getShaderProc32()(&state, x, y, dstC, count);
    145         return;
    146     }
    147 
    148     uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
    149     SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
    150     SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
    151     int max = state.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
    152 
    153     SkASSERT(state.fPixmap.addr());
    154 
    155     for (;;) {
    156         int n = count;
    157         if (n > max) {
    158             n = max;
    159         }
    160         SkASSERT(n > 0 && n < BUF_MAX*2);
    161 #ifdef TEST_BUFFER_OVERRITE
    162         for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
    163             buffer[BUF_MAX + i] = TEST_PATTERN;
    164         }
    165 #endif
    166         mproc(state, buffer, n, x, y);
    167 #ifdef TEST_BUFFER_OVERRITE
    168         for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
    169             SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
    170         }
    171 #endif
    172         sproc(state, buffer, n, dstC);
    173 
    174         if ((count -= n) == 0) {
    175             break;
    176         }
    177         SkASSERT(count > 0);
    178         x += n;
    179         dstC += n;
    180     }
    181 }
    182 
    183 SkShader::Context::ShadeProc SkBitmapProcShader::BitmapProcShaderContext::asAShadeProc(void** ctx) {
    184     if (fState->getShaderProc32()) {
    185         *ctx = fState;
    186         return (ShadeProc)fState->getShaderProc32();
    187     }
    188     return nullptr;
    189 }
    190 
    191 ///////////////////////////////////////////////////////////////////////////////
    192 
    193 #include "SkUnPreMultiply.h"
    194 #include "SkColorShader.h"
    195 #include "SkEmptyShader.h"
    196 
    197 // returns true and set color if the bitmap can be drawn as a single color
    198 // (for efficiency)
    199 static bool can_use_color_shader(const SkBitmap& bm, SkColor* color) {
    200 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
    201     // HWUI does not support color shaders (see b/22390304)
    202     return false;
    203 #endif
    204 
    205     if (1 != bm.width() || 1 != bm.height()) {
    206         return false;
    207     }
    208 
    209     SkAutoLockPixels alp(bm);
    210     if (!bm.readyToDraw()) {
    211         return false;
    212     }
    213 
    214     switch (bm.colorType()) {
    215         case kN32_SkColorType:
    216             *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
    217             return true;
    218         case kRGB_565_SkColorType:
    219             *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
    220             return true;
    221         case kIndex_8_SkColorType:
    222             *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
    223             return true;
    224         default: // just skip the other configs for now
    225             break;
    226     }
    227     return false;
    228 }
    229 
    230 static bool bitmap_is_too_big(const SkBitmap& bm) {
    231     // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
    232     // communicates between its matrix-proc and its sampler-proc. Until we can
    233     // widen that, we have to reject bitmaps that are larger.
    234     //
    235     static const int kMaxSize = 65535;
    236 
    237     return bm.width() > kMaxSize || bm.height() > kMaxSize;
    238 }
    239 
    240 SkShader* SkCreateBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
    241                                SkShader::TileMode tmy, const SkMatrix* localMatrix,
    242                                SkTBlitterAllocator* allocator) {
    243     SkShader* shader;
    244     SkColor color;
    245     if (src.isNull() || bitmap_is_too_big(src)) {
    246         if (nullptr == allocator) {
    247             shader = new SkEmptyShader;
    248         } else {
    249             shader = allocator->createT<SkEmptyShader>();
    250         }
    251     } else if (can_use_color_shader(src, &color)) {
    252         if (nullptr == allocator) {
    253             shader = new SkColorShader(color);
    254         } else {
    255             shader = allocator->createT<SkColorShader>(color);
    256         }
    257     } else {
    258         if (nullptr == allocator) {
    259             shader = new SkBitmapProcShader(src, tmx, tmy, localMatrix);
    260         } else {
    261             shader = allocator->createT<SkBitmapProcShader>(src, tmx, tmy, localMatrix);
    262         }
    263     }
    264     return shader;
    265 }
    266 
    267 ///////////////////////////////////////////////////////////////////////////////
    268 
    269 #ifndef SK_IGNORE_TO_STRING
    270 void SkBitmapProcShader::toString(SkString* str) const {
    271     static const char* gTileModeName[SkShader::kTileModeCount] = {
    272         "clamp", "repeat", "mirror"
    273     };
    274 
    275     str->append("BitmapShader: (");
    276 
    277     str->appendf("(%s, %s)",
    278                  gTileModeName[fTileModeX],
    279                  gTileModeName[fTileModeY]);
    280 
    281     str->append(" ");
    282     fRawBitmap.toString(str);
    283 
    284     this->INHERITED::toString(str);
    285 
    286     str->append(")");
    287 }
    288 #endif
    289 
    290 ///////////////////////////////////////////////////////////////////////////////
    291 
    292 #if SK_SUPPORT_GPU
    293 
    294 #include "GrTextureAccess.h"
    295 #include "SkGr.h"
    296 #include "effects/GrSimpleTextureEffect.h"
    297 
    298 const GrFragmentProcessor* SkBitmapProcShader::asFragmentProcessor(GrContext* context,
    299                                              const SkMatrix& viewM, const SkMatrix* localMatrix,
    300                                              SkFilterQuality filterQuality) const {
    301     SkMatrix matrix;
    302     matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());
    303 
    304     SkMatrix lmInverse;
    305     if (!this->getLocalMatrix().invert(&lmInverse)) {
    306         return nullptr;
    307     }
    308     if (localMatrix) {
    309         SkMatrix inv;
    310         if (!localMatrix->invert(&inv)) {
    311             return nullptr;
    312         }
    313         lmInverse.postConcat(inv);
    314     }
    315     matrix.preConcat(lmInverse);
    316 
    317     SkShader::TileMode tm[] = {
    318         (TileMode)fTileModeX,
    319         (TileMode)fTileModeY,
    320     };
    321 
    322     // Must set wrap and filter on the sampler before requesting a texture. In two places below
    323     // we check the matrix scale factors to determine how to interpret the filter quality setting.
    324     // This completely ignores the complexity of the drawVertices case where explicit local coords
    325     // are provided by the caller.
    326     bool doBicubic;
    327     GrTextureParams::FilterMode textureFilterMode =
    328             GrSkFilterQualityToGrFilterMode(filterQuality, viewM, this->getLocalMatrix(),
    329                                             &doBicubic);
    330     GrTextureParams params(tm, textureFilterMode);
    331     SkAutoTUnref<GrTexture> texture(GrRefCachedBitmapTexture(context, fRawBitmap, params));
    332 
    333     if (!texture) {
    334         SkErrorInternals::SetError( kInternalError_SkError,
    335                                     "Couldn't convert bitmap to texture.");
    336         return nullptr;
    337     }
    338 
    339     SkAutoTUnref<const GrFragmentProcessor> inner;
    340     if (doBicubic) {
    341         inner.reset(GrBicubicEffect::Create(texture, matrix, tm));
    342     } else {
    343         inner.reset(GrSimpleTextureEffect::Create(texture, matrix, params));
    344     }
    345 
    346     if (kAlpha_8_SkColorType == fRawBitmap.colorType()) {
    347         return GrFragmentProcessor::MulOutputByInputUnpremulColor(inner);
    348     }
    349     return GrFragmentProcessor::MulOutputByInputAlpha(inner);
    350 }
    351 
    352 #endif
    353