Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2012 The Android Open Source Project
      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 "SkImageFilter.h"
      9 
     10 #include "SkBitmap.h"
     11 #include "SkDevice.h"
     12 #include "SkReadBuffer.h"
     13 #include "SkWriteBuffer.h"
     14 #include "SkRect.h"
     15 #include "SkTDynamicHash.h"
     16 #include "SkValidationUtils.h"
     17 #if SK_SUPPORT_GPU
     18 #include "GrContext.h"
     19 #include "SkGrPixelRef.h"
     20 #include "SkGr.h"
     21 #endif
     22 
     23 SkImageFilter::Cache* gExternalCache;
     24 
     25 SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect)
     26   : fInputCount(inputCount),
     27     fInputs(new SkImageFilter*[inputCount]),
     28     fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)) {
     29     for (int i = 0; i < inputCount; ++i) {
     30         fInputs[i] = inputs[i];
     31         SkSafeRef(fInputs[i]);
     32     }
     33 }
     34 
     35 SkImageFilter::SkImageFilter(SkImageFilter* input, const CropRect* cropRect)
     36   : fInputCount(1),
     37     fInputs(new SkImageFilter*[1]),
     38     fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)) {
     39     fInputs[0] = input;
     40     SkSafeRef(fInputs[0]);
     41 }
     42 
     43 SkImageFilter::SkImageFilter(SkImageFilter* input1, SkImageFilter* input2, const CropRect* cropRect)
     44   : fInputCount(2), fInputs(new SkImageFilter*[2]),
     45     fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)) {
     46     fInputs[0] = input1;
     47     fInputs[1] = input2;
     48     SkSafeRef(fInputs[0]);
     49     SkSafeRef(fInputs[1]);
     50 }
     51 
     52 SkImageFilter::~SkImageFilter() {
     53     for (int i = 0; i < fInputCount; i++) {
     54         SkSafeUnref(fInputs[i]);
     55     }
     56     delete[] fInputs;
     57 }
     58 
     59 SkImageFilter::SkImageFilter(int inputCount, SkReadBuffer& buffer) {
     60     fInputCount = buffer.readInt();
     61     if (buffer.validate((fInputCount >= 0) && ((inputCount < 0) || (fInputCount == inputCount)))) {
     62         fInputs = new SkImageFilter*[fInputCount];
     63         for (int i = 0; i < fInputCount; i++) {
     64             if (buffer.readBool()) {
     65                 fInputs[i] = buffer.readImageFilter();
     66             } else {
     67                 fInputs[i] = NULL;
     68             }
     69             if (!buffer.isValid()) {
     70                 fInputCount = i; // Do not use fInputs past that point in the destructor
     71                 break;
     72             }
     73         }
     74         SkRect rect;
     75         buffer.readRect(&rect);
     76         if (buffer.isValid() && buffer.validate(SkIsValidRect(rect))) {
     77             uint32_t flags = buffer.readUInt();
     78             fCropRect = CropRect(rect, flags);
     79         }
     80     } else {
     81         fInputCount = 0;
     82         fInputs = NULL;
     83     }
     84 }
     85 
     86 void SkImageFilter::flatten(SkWriteBuffer& buffer) const {
     87     buffer.writeInt(fInputCount);
     88     for (int i = 0; i < fInputCount; i++) {
     89         SkImageFilter* input = getInput(i);
     90         buffer.writeBool(input != NULL);
     91         if (input != NULL) {
     92             buffer.writeFlattenable(input);
     93         }
     94     }
     95     buffer.writeRect(fCropRect.rect());
     96     buffer.writeUInt(fCropRect.flags());
     97 }
     98 
     99 bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src,
    100                                 const Context& context,
    101                                 SkBitmap* result, SkIPoint* offset) const {
    102     Cache* cache = context.cache();
    103     SkASSERT(result);
    104     SkASSERT(offset);
    105     SkASSERT(cache);
    106     if (cache->get(this, result, offset)) {
    107         return true;
    108     }
    109     /*
    110      *  Give the proxy first shot at the filter. If it returns false, ask
    111      *  the filter to do it.
    112      */
    113     if ((proxy && proxy->filterImage(this, src, context, result, offset)) ||
    114         this->onFilterImage(proxy, src, context, result, offset)) {
    115         cache->set(this, *result, *offset);
    116         return true;
    117     }
    118     return false;
    119 }
    120 
    121 bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
    122                                  SkIRect* dst) const {
    123     SkASSERT(&src);
    124     SkASSERT(dst);
    125     if (SkImageFilter::GetExternalCache()) {
    126         /*
    127          *  When the external cache is active, do not intersect the saveLayer
    128          *  bounds with the clip bounds. This is so that the cached result
    129          *  is always the full size of the primitive's bounds,
    130          *  regardless of the clip active on first draw.
    131          */
    132         *dst = SkIRect::MakeLargest();
    133         return true;
    134     }
    135     return this->onFilterBounds(src, ctm, dst);
    136 }
    137 
    138 void SkImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
    139     if (0 == fInputCount) {
    140         *dst = src;
    141         return;
    142     }
    143     if (this->getInput(0)) {
    144         this->getInput(0)->computeFastBounds(src, dst);
    145     } else {
    146         *dst = src;
    147     }
    148     for (int i = 1; i < fInputCount; i++) {
    149         SkImageFilter* input = this->getInput(i);
    150         if (input) {
    151             SkRect bounds;
    152             input->computeFastBounds(src, &bounds);
    153             dst->join(bounds);
    154         } else {
    155             dst->join(src);
    156         }
    157     }
    158 }
    159 
    160 bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const Context&,
    161                                   SkBitmap*, SkIPoint*) const {
    162     return false;
    163 }
    164 
    165 bool SkImageFilter::canFilterImageGPU() const {
    166     return this->asNewEffect(NULL, NULL, SkMatrix::I(), SkIRect());
    167 }
    168 
    169 bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx,
    170                                    SkBitmap* result, SkIPoint* offset) const {
    171 #if SK_SUPPORT_GPU
    172     SkBitmap input = src;
    173     SkASSERT(fInputCount == 1);
    174     SkIPoint srcOffset = SkIPoint::Make(0, 0);
    175     if (this->getInput(0) &&
    176         !this->getInput(0)->getInputResultGPU(proxy, src, ctx, &input, &srcOffset)) {
    177         return false;
    178     }
    179     GrTexture* srcTexture = input.getTexture();
    180     SkIRect bounds;
    181     if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
    182         return false;
    183     }
    184     SkRect srcRect = SkRect::Make(bounds);
    185     SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
    186     GrContext* context = srcTexture->getContext();
    187 
    188     GrTextureDesc desc;
    189     desc.fFlags = kRenderTarget_GrTextureFlagBit,
    190     desc.fWidth = bounds.width();
    191     desc.fHeight = bounds.height();
    192     desc.fConfig = kRGBA_8888_GrPixelConfig;
    193 
    194     GrAutoScratchTexture dst(context, desc);
    195     GrContext::AutoMatrix am;
    196     am.setIdentity(context);
    197     GrContext::AutoRenderTarget art(context, dst.texture()->asRenderTarget());
    198     GrContext::AutoClip acs(context, dstRect);
    199     GrEffectRef* effect;
    200     offset->fX = bounds.left();
    201     offset->fY = bounds.top();
    202     bounds.offset(-srcOffset);
    203     SkMatrix matrix(ctx.ctm());
    204     matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
    205     this->asNewEffect(&effect, srcTexture, matrix, bounds);
    206     SkASSERT(effect);
    207     SkAutoUnref effectRef(effect);
    208     GrPaint paint;
    209     paint.addColorEffect(effect);
    210     context->drawRectToRect(paint, dstRect, srcRect);
    211 
    212     SkAutoTUnref<GrTexture> resultTex(dst.detach());
    213     WrapTexture(resultTex, bounds.width(), bounds.height(), result);
    214     return true;
    215 #else
    216     return false;
    217 #endif
    218 }
    219 
    220 bool SkImageFilter::applyCropRect(const Context& ctx, const SkBitmap& src,
    221                                   const SkIPoint& srcOffset, SkIRect* bounds) const {
    222     SkIRect srcBounds;
    223     src.getBounds(&srcBounds);
    224     srcBounds.offset(srcOffset);
    225     SkRect cropRect;
    226     ctx.ctm().mapRect(&cropRect, fCropRect.rect());
    227     SkIRect cropRectI;
    228     cropRect.roundOut(&cropRectI);
    229     uint32_t flags = fCropRect.flags();
    230     if (flags & CropRect::kHasLeft_CropEdge) srcBounds.fLeft = cropRectI.fLeft;
    231     if (flags & CropRect::kHasTop_CropEdge) srcBounds.fTop = cropRectI.fTop;
    232     if (flags & CropRect::kHasRight_CropEdge) srcBounds.fRight = cropRectI.fRight;
    233     if (flags & CropRect::kHasBottom_CropEdge) srcBounds.fBottom = cropRectI.fBottom;
    234     if (!srcBounds.intersect(ctx.clipBounds())) {
    235         return false;
    236     }
    237     *bounds = srcBounds;
    238     return true;
    239 }
    240 
    241 bool SkImageFilter::applyCropRect(const Context& ctx, Proxy* proxy, const SkBitmap& src,
    242                                   SkIPoint* srcOffset, SkIRect* bounds, SkBitmap* dst) const {
    243     SkIRect srcBounds;
    244     src.getBounds(&srcBounds);
    245     srcBounds.offset(*srcOffset);
    246     SkRect cropRect;
    247     ctx.ctm().mapRect(&cropRect, fCropRect.rect());
    248     SkIRect cropRectI;
    249     cropRect.roundOut(&cropRectI);
    250     uint32_t flags = fCropRect.flags();
    251     *bounds = srcBounds;
    252     if (flags & CropRect::kHasLeft_CropEdge) bounds->fLeft = cropRectI.fLeft;
    253     if (flags & CropRect::kHasTop_CropEdge) bounds->fTop = cropRectI.fTop;
    254     if (flags & CropRect::kHasRight_CropEdge) bounds->fRight = cropRectI.fRight;
    255     if (flags & CropRect::kHasBottom_CropEdge) bounds->fBottom = cropRectI.fBottom;
    256     if (!bounds->intersect(ctx.clipBounds())) {
    257         return false;
    258     }
    259     if (srcBounds.contains(*bounds)) {
    260         *dst = src;
    261         return true;
    262     } else {
    263         SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds->width(), bounds->height()));
    264         if (!device) {
    265             return false;
    266         }
    267         SkCanvas canvas(device);
    268         canvas.clear(0x00000000);
    269         canvas.drawBitmap(src, srcOffset->x() - bounds->x(), srcOffset->y() - bounds->y());
    270         *srcOffset = SkIPoint::Make(bounds->x(), bounds->y());
    271         *dst = device->accessBitmap(false);
    272         return true;
    273     }
    274 }
    275 
    276 bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
    277                                    SkIRect* dst) const {
    278     if (fInputCount < 1) {
    279         return false;
    280     }
    281 
    282     SkIRect bounds;
    283     for (int i = 0; i < fInputCount; ++i) {
    284         SkImageFilter* filter = this->getInput(i);
    285         SkIRect rect = src;
    286         if (filter && !filter->filterBounds(src, ctm, &rect)) {
    287             return false;
    288         }
    289         if (0 == i) {
    290             bounds = rect;
    291         } else {
    292             bounds.join(rect);
    293         }
    294     }
    295 
    296     // don't modify dst until now, so we don't accidentally change it in the
    297     // loop, but then return false on the next filter.
    298     *dst = bounds;
    299     return true;
    300 }
    301 
    302 bool SkImageFilter::asNewEffect(GrEffectRef**, GrTexture*, const SkMatrix&, const SkIRect&) const {
    303     return false;
    304 }
    305 
    306 bool SkImageFilter::asColorFilter(SkColorFilter**) const {
    307     return false;
    308 }
    309 
    310 void SkImageFilter::SetExternalCache(Cache* cache) {
    311     SkRefCnt_SafeAssign(gExternalCache, cache);
    312 }
    313 
    314 SkImageFilter::Cache* SkImageFilter::GetExternalCache() {
    315     return gExternalCache;
    316 }
    317 
    318 #if SK_SUPPORT_GPU
    319 
    320 void SkImageFilter::WrapTexture(GrTexture* texture, int width, int height, SkBitmap* result) {
    321     SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
    322     result->setInfo(info);
    323     result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref();
    324 }
    325 
    326 bool SkImageFilter::getInputResultGPU(SkImageFilter::Proxy* proxy,
    327                                       const SkBitmap& src, const Context& ctx,
    328                                       SkBitmap* result, SkIPoint* offset) const {
    329     // Ensure that GrContext calls under filterImage and filterImageGPU below will see an identity
    330     // matrix with no clip and that the matrix, clip, and render target set before this function was
    331     // called are restored before we return to the caller.
    332     GrContext* context = src.getTexture()->getContext();
    333     GrContext::AutoWideOpenIdentityDraw awoid(context, NULL);
    334     if (this->canFilterImageGPU()) {
    335         return this->filterImageGPU(proxy, src, ctx, result, offset);
    336     } else {
    337         if (this->filterImage(proxy, src, ctx, result, offset)) {
    338             if (!result->getTexture()) {
    339                 const SkImageInfo info = result->info();
    340                 if (kUnknown_SkColorType == info.colorType()) {
    341                     return false;
    342                 }
    343                 GrTexture* resultTex = GrLockAndRefCachedBitmapTexture(context, *result, NULL);
    344                 result->setPixelRef(new SkGrPixelRef(info, resultTex))->unref();
    345                 GrUnlockAndUnrefCachedBitmapTexture(resultTex);
    346             }
    347             return true;
    348         } else {
    349             return false;
    350         }
    351     }
    352 }
    353 #endif
    354 
    355 static uint32_t compute_hash(const uint32_t* data, int count) {
    356     uint32_t hash = 0;
    357 
    358     for (int i = 0; i < count; ++i) {
    359         uint32_t k = data[i];
    360         k *= 0xcc9e2d51;
    361         k = (k << 15) | (k >> 17);
    362         k *= 0x1b873593;
    363 
    364         hash ^= k;
    365         hash = (hash << 13) | (hash >> 19);
    366         hash *= 5;
    367         hash += 0xe6546b64;
    368     }
    369 
    370     //    hash ^= size;
    371     hash ^= hash >> 16;
    372     hash *= 0x85ebca6b;
    373     hash ^= hash >> 13;
    374     hash *= 0xc2b2ae35;
    375     hash ^= hash >> 16;
    376 
    377     return hash;
    378 }
    379 
    380 class CacheImpl : public SkImageFilter::Cache {
    381 public:
    382     explicit CacheImpl(int minChildren) : fMinChildren(minChildren) {}
    383     virtual ~CacheImpl();
    384     bool get(const SkImageFilter* key, SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
    385     void set(const SkImageFilter* key, const SkBitmap& result, const SkIPoint& offset) SK_OVERRIDE;
    386     void remove(const SkImageFilter* key) SK_OVERRIDE;
    387 private:
    388     typedef const SkImageFilter* Key;
    389     struct Value {
    390         Value(Key key, const SkBitmap& bitmap, const SkIPoint& offset)
    391             : fKey(key), fBitmap(bitmap), fOffset(offset) {}
    392         Key fKey;
    393         SkBitmap fBitmap;
    394         SkIPoint fOffset;
    395         static const Key& GetKey(const Value& v) {
    396             return v.fKey;
    397         }
    398         static uint32_t Hash(Key key) {
    399             return compute_hash(reinterpret_cast<const uint32_t*>(&key), sizeof(Key) / sizeof(uint32_t));
    400         }
    401     };
    402     SkTDynamicHash<Value, Key> fData;
    403     int fMinChildren;
    404 };
    405 
    406 bool CacheImpl::get(const SkImageFilter* key, SkBitmap* result, SkIPoint* offset) {
    407     Value* v = fData.find(key);
    408     if (v) {
    409         *result = v->fBitmap;
    410         *offset = v->fOffset;
    411         return true;
    412     }
    413     return false;
    414 }
    415 
    416 void CacheImpl::remove(const SkImageFilter* key) {
    417     Value* v = fData.find(key);
    418     if (v) {
    419         fData.remove(key);
    420         delete v;
    421     }
    422 }
    423 
    424 void CacheImpl::set(const SkImageFilter* key, const SkBitmap& result, const SkIPoint& offset) {
    425     if (key->getRefCnt() >= fMinChildren) {
    426         fData.add(new Value(key, result, offset));
    427     }
    428 }
    429 
    430 SkImageFilter::Cache* SkImageFilter::Cache::Create(int minChildren) {
    431     return new CacheImpl(minChildren);
    432 }
    433 
    434 CacheImpl::~CacheImpl() {
    435     SkTDynamicHash<Value, Key>::Iter iter(&fData);
    436 
    437     while (!iter.done()) {
    438         Value* v = &*iter;
    439         ++iter;
    440         delete v;
    441     }
    442 }
    443